【问题标题】:Dynamic pivot null to 0动态将空值设为 0
【发布时间】:2013-09-02 15:10:37
【问题描述】:

我有一个存储过程,它从一个表中获取数据,运行我的动态数据透视存储过程,然后输出到页面中。问题是,有大量的空条目。当我在页面上处理这些数据时,我需要添加每个 TerminalID 的每个燃料数量。当它遇到空条目时会出现问题。我不想让程序读取每一行和每一列以将 null 转换为 0,并且希望在 SP 中这样做。

为了测试,我制作了这个脚本:

DECLARE @QUERY NVARCHAR(MAX)
    ,   @Soucecolumn VARCHAR(MAX)
    ,   @BeginningDate VARCHAR(MAX)
    ,   @EndingDate VARCHAR(MAX)
    ,   @CompanyID VARCHAR(2)

SET NOCOUNT ON;

SET @BeginningDate = CONVERT(VARCHAR(30), CAST('2004-01-01' AS DATE));
SET @EndingDate = CONVERT(VARCHAR(30), CAST('2007-01-01' AS DATE));
SET @CompanyID = CONVERT(INT, '2');
SET @Soucecolumn = STUFF((
    SELECT DISTINCT ', \[' + CAST(FuelTypeID AS VARCHAR(4)) + '\]'
    FROM tt_Manifest_Fuel_Distribution
    FOR XML PATH ('')), 1, 1, '')

SET @QUERY = '(
SELECT ManifestID, TerminalID, ' + @Soucecolumn + ' 
FROM (
    SELECT mfd.ManifestID, m.TerminalID, mfd.FuelTypeID, mfd.FuelQuantity 
    FROM tt_Manifest_Fuel_Distribution mfd, tt_Terminals t, tt_Fuel_Types ft, tt_Manifests m
    WHERE mfd.FuelTypeID=ft.FuelTypeID
        AND m.ManifestID=mfd.ManifestID
        AND m.CompanyID= ' + @CompanyID + ' 
        AND m.ManifestInsertDate BETWEEN ''' + @BeginningDate + ''' AND ''' + @EndingDate +
        ''' 
) up 
PIVOT (
    MAX(FuelQuantity) FOR \[FuelTypeID\] IN (' + @Soucecolumn + ')
) AS pvt)'

EXEC sp_executesql @QUERY

样本数据是:

>ManifestID   TerminalID   3   6   4   2   1   5
>417    1   NULL    NULL    NULL    NULL    NULL    2478
>421    1   NULL    NULL    NULL    NULL    3458    NULL
>508    1   NULL    NULL    NULL    NULL    NULL    2471
>826    1   NULL    NULL    NULL    NULL    NULL    7464
>832    1   NULL    NULL    NULL    NULL    3482    NULL
>833    1   1001    NULL    NULL    NULL    1492    NULL
>844    1   NULL    NULL    NULL    NULL    2498    NULL
>870    1   NULL    NULL    NULL    NULL    5991    2503
>872    1   NULL    NULL    NULL    NULL    3494    NULL
>2      2   NULL    NULL    5514    NULL    NULL    2505
>43     2   NULL    NULL    NULL    NULL    7011    NULL
>46     2   1005    NULL    NULL    NULL    5007    2510
>60     2   NULL    NULL    3502    NULL    NULL    4513
>63     2   NULL    NULL    4505    NULL    NULL    3008
>69     2   NULL    NULL    4008    NULL    4508    NULL
>78     2   1007    NULL    NULL    NULL    5022    NULL
>79     2   NULL    NULL    2505    NULL    NULL    NULL

我尝试在 mfd.FuelQuantity 和 @Sourcecolumn 周围放置 ISNULL(,0)。 mfd.FuelQuantiity 似乎没有变化,而 @Sourcecolumn 错误地声称 ISNull() 需要 2 个参数。

我看错了吗?

【问题讨论】:

    标签: sql sql-server stored-procedures pivot-table


    【解决方案1】:

    我强烈建议不要使用已弃用的隐式连接。

    您需要将ISNULL() 合并到SELECT 子句中@sourcecolumn 列表中的每个项目中。它引发错误的原因是因为您的整个列列表都包含在一个语句中:ISNULL(col1,col2,col3...,0) you need ISNULL(col1,0),ISNULL(col2,0)...

    我建议制作一个单独的 sourcecolumn 变量以在您的 SELECT 中使用。

    类似:

    SET @Sourcecolumn2 = STUFF((SELECT distinct ',ISNULL(\[' + CAST(FuelTypeID as varchar(4)) + ',0)\]as '+ CAST(FuelTypeID as varchar(4)) +'     FROM tt_Manifest_Fuel_Distribution
    FOR XML PATH('')),1,1,'') 
    

    所以最终:

    ![Declare    @QUERY NVARCHAR(MAX), 
    @Soucecolumn VARCHAR(MAX),
    @Sourcecolumn2 VARCHAR(MAX),
    @BeginningDate VARCHAR(MAX),
    @EndingDate VARCHAR(MAX),
    @CompanyID VARCHAR(2)
    SET NOCOUNT ON;
    SET @BeginningDate = convert(varchar(30), cast('2004-01-01' as date));
    SET @EndingDate = convert(varchar(30), cast('2007-01-01' as date));
    SET @CompanyID = convert(int, '2');
    SET @Soucecolumn = STUFF((SELECT distinct ', \[' + CAST(FuelTypeID as varchar(4)) + '\]'     FROM tt_Manifest_Fuel_Distribution
    FOR XML PATH('')),1,1,''); 
    SET @Sourcecolumn2 = STUFF((SELECT distinct ',ISNULL(\[' + CAST(FuelTypeID as varchar(4)) + ',0)\] as '+ CAST(FuelTypeID as varchar(4))+'     FROM tt_Manifest_Fuel_Distribution
    FOR XML PATH('')),1,1,''); 
    SET @QUERY = '(SELECT ManifestID, TerminalID, ' + @Sourcecolumn2 + ' FROM (
    SELECT mfd.ManifestID, m.TerminalID, mfd.FuelTypeID, mfd.FuelQuantity 
    FROM tt_Manifest_Fuel_Distribution mfd, tt_Terminals t, tt_Fuel_Types ft, tt_Manifests m
    WHERE mfd.FuelTypeID=ft.FuelTypeID
    AND m.ManifestID=mfd.ManifestID
    AND m.CompanyID= ' + @CompanyID + ' 
    AND m.ManifestInsertDate BETWEEN ''' + @BeginningDate + ''' AND ''' + @EndingDate + 
    ''' ) up PIVOT (MAX(FuelQuantity) FOR \[FuelTypeID\] IN (' + @Soucecolumn + ')) AS pvt)'
    exec sp_executesql  @QUERY][1]
    

    【讨论】:

    • 它现在给了我所有值的燃料类型 ID 与燃料数量:
    • 45 1 1 3 2 5 6 4 68 1 1 3 2 5 6 4 91 1 1 3 2 5 6 4 105 1 1 3 2 5 6 4 298 1 1 3 2 5 6 4 415 1 1 3 2 5 6 4 417 1 1 3 2 5 6 4
    • 我没有注意到你的列名,只需要在我添加的部分添加括号,查看更新的答案。
    • 它就像一个魅力,虽然现在我错过了数量的列名。
    • 我想我可能已经修好了。如果您可以为我验证: SET @Sourcecolumn2 = STUFF((SELECT distinct ',ISNULL([' + CAST(FuelTypeID as varchar(4)) + '],0) as Column' + CAST(FuelTypeID as varchar(4) ) FROM tt_Manifest_Fuel_Distribution
    【解决方案2】:

    考虑下表

    这是样本数据

    SELECT * INTO #TEMP
    FROM
    (
        SELECT '01/JAN/2014' [DATE],'A' NAME,100 MARKS
        UNION ALL
        SELECT '02/JAN/2014' [DATE],'A' NAME,120
        UNION ALL
        SELECT '02/JAN/2014' [DATE],'B' NAME,130
        UNION ALL
        SELECT '03/JAN/2014' [DATE],'B' NAME,115
        UNION ALL
        SELECT '01/JAN/2014' [DATE],'C' NAME,123
        UNION ALL
        SELECT '01/JAN/2014' [DATE],'C' NAME,134
        UNION ALL
        SELECT '03/JAN/2014' [DATE],'C' NAME,146
        UNION ALL
        SELECT '04/JAN/2014' [DATE],'C' NAME,149
    )TAB
    

    现在选择一个变量的不同名称以进行数据透视

    DECLARE @cols NVARCHAR (MAX)
    SET @cols = SUBSTRING((SELECT DISTINCT ',['+NAME+']' 
    FROM #TEMP GROUP BY NAME FOR XML PATH('')),2,8000)
    

    现在您需要另一个变量来应用 NULL to zero 逻辑

    DECLARE @NulltoZeroCols NVARCHAR (MAX)
    SET @NulltoZeroCols = SUBSTRING((SELECT DISTINCT ',ISNULL(['+NAME+'],0) AS ['+NAME+']' 
    FROM #TEMP GROUP BY NAME FOR XML PATH('')),2,8000)
    

    现在使用两个变量旋转查询

    DECLARE @query NVARCHAR(MAX)
    SET @query = 'SELECT DATE,' + @NulltoZeroCols + ' FROM 
                 (
                     SELECT [DATE],NAME,MARKS FROM #TEMP
                 ) x
                 PIVOT 
                 (
                     SUM(MARKS)
                     FOR [NAME] IN (' + @cols + ')
                ) p
                ;'
    EXEC SP_EXECUTESQL @query
    

    最后你的结果如下

    【讨论】:

      猜你喜欢
      • 2021-08-09
      • 1970-01-01
      • 2013-07-30
      • 2014-01-30
      • 2019-06-14
      • 2015-12-04
      • 2022-11-12
      • 2010-11-06
      • 2020-11-07
      相关资源
      最近更新 更多