首页 > 解决方案 > 使用来自一个 DataTable 的数据来获取另一个 DataTable 的结果

问题描述

我目前有一个导出到 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";

        }

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

(PerDiff 开始是PerDiff02因为之前没有任何东西201501可以比较。)

如果有任何不清楚的地方,请告诉我,我会尽力澄清!我对 C# 还是有点陌生​​,尤其是datatables.

我试图在 SQL 中尝试这个,但是我仍然是 SQL 的新手,并且认为这会更容易通过 C# 实现。一旦我让它工作,就会考虑优化。

如果有任何反对意见,我要求您解释为什么反对,以便我更正!

标签: c#datatables

解决方案


好的,这就是我 2 年前为类似的事情所做的

在您的内部选择上添加占位符的差异

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

在 EXECUTE 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 破坏任何其他内容


推荐阅读