使用一个数据表中的数据获取另一个数据表的结果

时间:2018-10-15 15:36:34

标签: c# datatables

我目前有一个存储过程,可以将其导出到DataTable(dt)。提供的数据显示每个客户平均每个月的价值。如果数据具有要显示的值,则数据必须显示其值。

这是我的存储过程(动态数据透视表)的SQL:

ALTER Procedure [dbo].[stpMonthlyAvg]
--Parameters
AS
Begin

Begin Tran T1;

    Begin Try

        DECLARE @Dates NVARCHAR(MAX);

        SELECT @Dates = CONCAT(@Dates + ', ', QUOTENAME(BalMonth))
        FROM vAvgMonBal
        GROUP BY BalMonth
        ORDER BY BalMonth;

        DECLARE @DynSQL NVARCHAR(MAX),
                @months NVARCHAR(255);

        SET @months = 'CONCAT( CONVERT(nvarchar(15), YEAR(BalDate)) , IIF(LEN(MONTH(BalDate)) > 1, CONVERT(nvarchar(15), MONTH(BalDate)), ''0'' + CONVERT(nvarchar(15), MONTH(BalDate))))'
        SET @DynSQL = 'SELECT *
                       FROM
                           (SELECT 
                                a1.IDNbr, 
                                a2.CustName, ' + @months + ' AS BalMonth,
                                AVG(a1.Balance) as Balance
                            FROM tblID a1 
                            INNER JOIN tblCust a2 ON (a1.IDNbr = a2.IDNbr)
                            WHERE a2.CustType != ''Inactive'' AND a2.CustType IS NOT NULL AND a1.Balance != 0 
                            GROUP BY 
                                a1.IDNbr, a2.CustName, ' + @months +') as d1
        PIVOT (
            AVG(Balance)
            FOR BalMonth IN (' + @Dates + ')
        ) piv';

        EXECUTE sp_executesql @DynSQL

    Commit Tran T1;

End Try

Begin Catch

    RollBack Tran T1;
End Catch

End

这是我当前拥有的表格的示例-带有测试数据:

+-------------------------------------------------------+
| ID | CustName | 201501 | 201502 | 201503 | 201504 | ..|
+-------------------------------------------------------+
| 32 | CustOne  | 100.00 | 200.00 | 400.00 | 700.00 | ..|
| 56 | CustTwo  | 350.00 | 375.00 | 400.00 | 500.00 | ..|
| 89 | CustThree| 222.22 | 333.33 | 444.44 | 555.55 | ..|
| .. | ...      |   ..   |   ..   |   ..   |   ..   | ..|
+-------------------------------------------------------+

我需要找到每个客户每个月与上个月之间的百分比差异,并将其添加到其自己的DataTable(fDt)中。

这就是我需要的(行中的值是百分比):

+-------------------------------------------------------+
| ID | CustName | PerDiff02 | PerDiff03 | PerDiff04 | ..|
+-------------------------------------------------------+
| 32 | CustOne  |     0     |     100   |     200   | ..|
| 56 | CustTwo  |   93.33   |    93.75  |    80.00  | ..|
| 89 | CustThree|   66.66   |    75.00  |    80.00  | ..|
| .. | ...      |   ....    |    ....   |    ....   | ..|
+-------------------------------------------------------+

我目前正在将数据添加到fDt中,尽管它是按列而不是按行计算的(我认为)。

意味着我的数据输出如下:

+-------------------------------------------------------+
| ID | CustName | PerDiff02 | PerDiff03 | PerDiff04 | ..|
+-------------------------------------------------------+
| 32 | CustOne  |     0     |    100    |    200    | ..|
| 56 | CustTwo  |     0     |    100    |    200    | ..|
| 89 | CustThree|     0     |    100    |    200    | ..|
| .. | ...      |   ....    |   ....    |   ....    | ..|
+-------------------------------------------------------+

为整个列分配一次计算的结果。

这是我正在使用的代码:

        Uni.fileExport Export = new Uni.fileExport();
        string conStr = "Data Source=" + ConfigurationManager.AppSettings["DataSource"] + "Initial Catalog=" + ConfigurationManager.AppSettings["InitialCatalog"] + "Integrated Security=True;";

        var dt = new DataTable();
        dt = Export.sqlToDTMonthlyAvg(conStr, stp);
        var fDt = new DataTable();

        int i;
        int fieldCount = dt.Columns.Count;
        int finalSize = (fieldCount) * 2;
        string[] finalCol = new string[finalSize];
        string[] colHeaders = new string[fieldCount];

        for (i = 0; i < fieldCount; i++)
        {
            colHeaders[i] = dt.Columns[i].ToString();
        }

        fDt.Columns.Add(colHeaders[0]);
        fDt.Columns.Add(colHeaders[1]);



        for (i = 1; i < dt.Rows.Count; i++)
        {
            fDt.Rows.Add(dt.Rows[i][0], dt.Rows[i][1]);
        }


        /* 
         * This section is meant to try and get the percent difference from dt 
         * to fDt. Looking into doing this from the SQL data base rather than from the code
         * in order to save processing at runTime. The main concern being the stored procedure
         * taking longer than a couple minutes. 
         */

        // Gets the column headers for dataTable fDt
        for (i = 2; i <= (dt.Columns.Count - 2); i++)
        {
            string colName = "PerDiff" + dt.Columns[i + 1];
            fDt.Columns.Add(colName, typeof(decimal));
        }

        for (i = 2; i <= (dt.Columns.Count - 2); i++)
        {
            var month1 = dt.Columns[i];
            var month2 = dt.Columns[i + 1];
            fDt.Columns[i].Expression = $"({month1} / {month2}) * 100";

        }

问题:如何获得dtfDt列的百分比差异?我需要基于上个月的百分比。

(由于PerDiff02之前没有可比较的事实,因此PerDiff从201501开始。)

如果不清楚,请告诉我,我将尽力澄清!我对C#还是有点陌生​​,尤其是datatables

我尝试在SQL中尝试此操作,但是我仍然还是SQL的新手,因此认为可以通过C#轻松实现。一旦开始运行,便会考虑优化。

如果有任何不赞成票,请您解释为什么要不赞成票,以便我予以纠正!

2 个答案:

答案 0 :(得分:1)

好吧,这是我2年前做的类似事情

在内部选择中,添加占位符的差异

SELECT 
                                a1.IDNbr, 
                                a2.CustName, ' + @months + ' AS BalMonth,
                                AVG(a1.Balance) as Balance,
0 as Diff1,0 as Diff2,0 as Diff3

在执行sp_executesql @DynSQL添加之前

DECLARE @DataProcess TABLE // Table variable to hold everything
    (
        NewTableID INT IDENTITY(1,1)
        ,  Id INT
        , CustName NVARCHAR(256)
        , Month1 NVARCHAR(260)
        , Month2 NVARCHAR(260)
        , Month3 NVARCHAR(260)
        , Month4 NVARCHAR(260)
        ,Diff1 INT
        ,Diff2 INT
        ,Diff3 INT
    )




    INSERT INTO @DataProcess EXECUTE sp_executesql @DynSQL // fill in the data 

Now declare values and loop 
DECLARE @Count INT, @Counter INT, @Id INT,@Month1  NVARCHAR(260),@Month1  NVARCHAR(260),@Month3  NVARCHAR(260),@Month4  NVARCHAR(260)

SELECT @Count = COUNT(*) FROM @DataProcess d
    SET @Counter = 1

BEGIN
        SELECT @Id = ID,(260),@Month1 =  Month1,@Month2=Month1 ,@Month3=Month3 ,@Month4 =Month3    FROM @DataProcess m WHERE NewTableID  = Counter

        m.Diff1 =@Month2 - @Month1;
        m.Diff2 =@Month3 - @Month2
         m.Diff2 =@Month4 - @Month3

        SET @Counter = @Counter + 1
 END    

这应该为您填满所有内容,并且不要使用sp

答案 1 :(得分:1)

每个请求都是我在存储过程中要做的全部事情

Begin Tran T1;

    Begin Try

        DECLARE @Dates NVARCHAR(MAX);

        SELECT @Dates = CONCAT(@Dates + ', ', QUOTENAME(BalMonth))
        FROM vAvgMonBal
        GROUP BY BalMonth
        ORDER BY BalMonth;

        DECLARE @DynSQL NVARCHAR(MAX),
                @months NVARCHAR(255);

        SET @months = 'CONCAT( CONVERT(nvarchar(15), YEAR(BalDate)) , IIF(LEN(MONTH(BalDate)) > 1, CONVERT(nvarchar(15), MONTH(BalDate)), ''0'' + CONVERT(nvarchar(15), MONTH(BalDate))))'
        SET @DynSQL = 'SELECT *
                       FROM
                           (SELECT 
                                a1.IDNbr, 
                                a2.CustName, ' + @months + ' AS BalMonth,
                                AVG(a1.Balance) as Balance,
                0 as Diff1,0 as Diff2,0 as Diff3
                            FROM tblID a1 
                            INNER JOIN tblCust a2 ON (a1.IDNbr = a2.IDNbr)
                            WHERE a2.CustType != ''Inactive'' AND a2.CustType IS NOT NULL AND a1.Balance != 0 
                            GROUP BY 
                                a1.IDNbr, a2.CustName, ' + @month +') as d1
        PIVOT (
            AVG(Balance)
            FOR BalMonth IN (' + @Dates + ')
        ) piv';

        DECLARE @DataProcess TABLE // Table variable to hold everything
    (
        NewTableID INT IDENTITY(1,1)
        ,  Id INT
        , CustName NVARCHAR(256)
        , Month1 NVARCHAR(260)
        , Month2 NVARCHAR(260)
        , Month3 NVARCHAR(260)
        , Month4 NVARCHAR(260)
        ,Diff1 INT
        ,Diff2 INT
        ,Diff3 INT
    )




    INSERT INTO @DataProcess EXECUTE sp_executesql @DynSQL // fill in the data 
Now declare values and loop 
DECLARE @Count INT, @Counter INT, @Id INT,@Month1  NVARCHAR(260),@Month1  NVARCHAR(260),@Month3  NVARCHAR(260),@Month4  NVARCHAR(260)

SELECT @Count = COUNT(*) FROM @DataProcess d
    SET @Counter = 1

BEGIN
        SELECT @Id = ID,(260),@Month1 =  Month1,@Month2=Month1 ,@Month3=Month3 ,@Month4 =Month3    FROM @DataProcess m WHERE NewTableID  = Counter

        m.Diff1 =@Month2 - @Month1;
        m.Diff2 =@Month3 - @Month2
         m.Diff2 =@Month4 - @Month3

        SET @Counter = @Counter + 1
 END    

select * from @DataProcess // this reads all the data in the Temp Table and this is what fills your data table in .NEt
    Commit Tran T1;

End Try

Begin Catch

    RollBack Tran T1;
End Catch

End