SQL-从动态SQL获取百分比差异

时间:2018-09-21 15:28:19

标签: sql sql-server

我目前有一个动态存储过程,该过程每个月都在数据库中使用,并平均每天的值。

我目前所拥有的(值是该月的总体平均值):

+-------------------------------------------------------+
| ID | CustName | 201501 | 201502 | 201503 | 201504 | ..|
+-------------------------------------------------------+
| 32 | CustOne  | 5852.25| 5847.50| 6542.98| 7585.25| ..|
| 56 | CustTwo  | 5452.45| 7852.50| 6985.41| 1245.21| ..|
| 89 | CustThree| 8520.25| 7410.01| 9630.36| 1245.32| ..|
| .. | ...      |   ..   |   ..   |   ..   |   ..   | ..|
+-------------------------------------------------------+

这是我用来创建上表的存储过程:

DECLARE @Dates NVARCHAR(MAX);

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

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

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


EXECUTE sp_executesql @DynSQL

问题:如何从上一个存储过程中获取数据并从中获得百分比差异(Month1/Month2) * 100,如下所示?我期望我需要一个新的存储过程或添加到我当前拥有的存储过程中。

我需要什么(每个“ PerDiff”是上个月与上表示例的百分比差异):

+---------------------------------------------------------------+
| ID | CustName | PerDiff1 | PerDiff2 | PerDiff3 | PerDiff4 | ..|
+---------------------------------------------------------------+
| 32 | CustOne  |  100.00  |   68.12  |  654.25  |  483.36  | ..|
| 56 | CustTwo  |   58.21  |  154.54  |  932.45  |   58.45  | ..|
| 89 | CustThree|  965.25  |  951.58  |  689.12  |   32.50  | ..|
| .. | ...      |   ....   |   ....   |   ....   |   ....   | ..|
+---------------------------------------------------------------+

我尝试使用类似的东西:

DECLARE @PerDiff nvarchar(max);

SET @PerDiff = 'SELECT *
FROM (' + @DynSQL + ')'

EXECUTE sp_executesql @PerDiff

至少要尝试移动数据。

我不再收到任何错误消息-我通常只是停留在如何继续进行动态应用数学上。

任何帮助或建议将不胜感激!

EDIT1 :这是已完成的@DynSQL的结果

SELECT *
FROM
(
SELECT a1.DDANbr, 
a2.CustName, 
CONCAT( CONVERT(nvarchar(15), YEAR(BalDate)) , IIF(LEN(MONTH(BalDate)) > 1, CONVERT(nvarchar(15), MONTH(BalDate)), '0' + CONVERT(nvarchar(15), MONTH(BalDate))))AS BalMonth,
a1.Balance

FROM tblID a1 INNER JOIN tblCust a2 ON (a1.IDNbr = a2.IDNbr)

WHERE a2.CustType != 'Inactive'

GROUP BY a1.IDNbr, a2.CustName, BalDate, a1.Balance
) as d1
PIVOT (
AVG(Balance)
FOR BalMonth IN ([201501], [201502], [201503], [201504], [201505], [201506], [201507], [201508], [201509], [201510], [201511], [201512], [201601], [201602], [201603], [201604], [201605], [201606], [201607], [201608], [201609], [201610], [201611], [201612], [201701], [201702], [201703], [201704], [201705], [201706], [201707], [201708], [201709], [201710], [201711], [201712], [201801], [201802], [201803], [201804], [201805], [201806], [201807], [201808], [201809])
) piv

2 个答案:

答案 0 :(得分:1)

进行查询并将其设为派生表时,必须为该表指定别名。

赞:

DECLARE @PerDiff nvarchar(max);

SET @PerDiff = 'SELECT IDNbr, CustName, ' + @months + '
FROM (' + @DynSQL + ') t1'

EXECUTE sp_executesql @DynSQL, @PerDiff

答案 1 :(得分:0)

DECLARE @Dates NVARCHAR(MAX);

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

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

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


EXECUTE sp_executesql @DynSQL