动态pivot null为0

时间:2013-09-02 15:10:38

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

我有一个存储过程,它从一个表中获取数据,运行我的动态数据透视存储过程,然后输出到页面中。问题是,有大量的空条目。当我在页面上处理这些数据时,我需要为每个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个参数。

我是以错误的方式看待这个吗?

2 个答案:

答案 0 :(得分:2)

我强烈建议远离弃用的隐式联接。

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

我建议您在SELECT中使用单独的sourcecolumn变量。

类似的东西:

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]

答案 1 :(得分:1)

考虑下表

enter image description here

以下是示例数据

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

现在为pivot的变量选择不同的名称

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

最后你的结果如下

enter image description here