创建动态数据透视表列名称

时间:2019-08-16 14:45:48

标签: sql-server pivot

我创建了带有硬编码列名的数据透视表。数据透视表只是按数量(当月+ 11个月前)保持滚动销售总额。

这是我第一次正确使用PIVOT函数,并且代码运行正常。

SELECT
    Item_Code_Desc,
    ISNULL([Current],0)     AS [Current],
    ISNULL([1],0)           AS [1],
    ISNULL([2],0)           AS [2],
    ISNULL([3],0)           AS [3],
    ISNULL([4],0)           AS [4],
    ISNULL([5],0)           AS [5],
    ISNULL([6],0)           AS [6],
    ISNULL([7],0)           AS [7],
    ISNULL([8],0)           AS [8],
    ISNULL([9],0)           AS [9],
    ISNULL([10],0)          AS [10],
    ISNULL([11],0)          AS [11]
FROM
    (SELECT
         CONCAT(ST.Code,' - ', ST.Description_1) AS Item_Code_Desc,
         STT.ActualQuantity AS Qty,
         CASE
            WHEN MONTH(STT.TxDate) = MONTH(GETDATE()) THEN 'Current'
            WHEN MONTH(STT.TxDate) = MONTH(DATEADD(MONTH, -1, GETDATE())) THEN '1'
            WHEN MONTH(STT.TxDate) = MONTH(DATEADD(MONTH, -2, GETDATE())) THEN '2'
            WHEN MONTH(STT.TxDate) = MONTH(DATEADD(MONTH, -3, GETDATE())) THEN '3'
            WHEN MONTH(STT.TxDate) = MONTH(DATEADD(MONTH, -4, GETDATE())) THEN '4'
            WHEN MONTH(STT.TxDate) = MONTH(DATEADD(MONTH, -5, GETDATE())) THEN  '5'
            WHEN MONTH(STT.TxDate) = MONTH(DATEADD(MONTH, -6, GETDATE())) THEN '6'
            WHEN MONTH(STT.TxDate) = MONTH(DATEADD(MONTH, -7, GETDATE())) THEN '7'
            WHEN MONTH(STT.TxDate) = MONTH(DATEADD(MONTH, -8, GETDATE())) THEN '8'
            WHEN MONTH(STT.TxDate) = MONTH(DATEADD(MONTH, -9, GETDATE())) THEN   '9'
            WHEN MONTH(STT.TxDate) = MONTH(DATEADD(MONTH, -10, GETDATE())) THEN '10'
            WHEN MONTH(STT.TxDate) = MONTH(DATEADD(MONTH, -11, GETDATE())) THEN '11'
            ELSE '0'
         END AS [Period]
     FROM 
         _bvSTTransactionsFull AS STT
     INNER JOIN 
         StkItem AS ST ON STT.AccountLink = ST.StockLink
     WHERE 
         STT.TxDate >= DATEADD(MONTH, -11, DATEADD(MONTH, DATEDIFF(MONTH, 0, GETDATE()), 0))
         AND STT.Module = 'AR') AS P
PIVOT  
    (SUM(P.Qty)
        FOR P.Period IN ([1],[2],[3],[4],[5],[6],[7],[8],[9],[10],[11],[Current])
    ) AS PVT

为使输出更具动态性,我想将月份和年份显示为字段标题,而不只是显示1,2,3等。

为此,我先取出原始的CASE,然后使用CONCAT函数获得所需的结果

CONCAT(DATENAME(MONTH,STT.TxDate),' ',YEAR(STT.TxDate))                     AS [Period],

现在,子查询以“ mmmm yyyy”格式显示交易日期,我希望表格以此为中心。我确实想知道在到达终点时将如何执行此操作,因为列名不再是硬编码的。

尝试

 PIVOT (
            SUM(P.Qty)
        FOR  CONCAT(DATENAME(MONTH,P.TxDate),' ',YEAR(P.TxDate)) 
            ) AS PVT

我做了很多其他的研究,发现这个过程比我想象的要复杂一些。

我以前没有使用过STUFF和FOR XML PATH。我试图将以上内容转换为我在网上找到的示例。但是我正在尝试尝试,因为我不了解我要做的事情的核心逻辑。

请我不仅在如何使轴动态变化方面获得帮助,还可能需要一些注释以进一步了解正在发生的事情。非常感谢您的帮助!

尝试后

这是我做对的尝试:

DECLARE
@Cols NVARCHAR(MAX),
@Query NVARCHAR(MAX),
@Module NVARCHAR = 'AR'

 SELECT 
@Cols = STUFF((SELECT DISTINCT ',' + 'CONCAT(DATENAME(MONTH, STT.TxDate),,YEAR(STT.TxDate))' + QUOTENAME(NAME)
                FROM _bvSTTransactionsFull AS STT
                WHERE STT.Module = 'AR'
                FOR XML PATH (''), TYPE).VALUE('.','NVARCHAR(MAX)'),1,1,'')
 SELECT
@Query = '
SELECT
Item_Code,
Item_Desc,
' +''''+ @Cols + '''''
FROM
 (SELECT
     ST.Code                                                                            AS Item_Code, 
     ST.Description_1                                                                   AS Item_Desc,
     STT.ActualQuantity                                                                 AS Qty,
     CONCAT(DATENAME(MONTH, STT.TxDate),,YEAR(STT.TxDate))                              AS [Period]
 FROM 
     _bvSTTransactionsFull AS STT
 INNER JOIN 
     StkItem AS ST ON STT.AccountLink = ST.StockLink
 WHERE 
     STT.TxDate >= DATEADD(MONTH, -13, DATEADD(MONTH, DATEDIFF(MONTH, 0, 
 GETDATE()), 0))
     AND STT.Module = '+ @Module +') AS P
 PIVOT  
(SUM(P.Qty)
    FOR P.Period IN ('+@cols+')
) AS PVT '
PRINT @Query
EXEC (@Query)

但是我遇到以下错误:

  

信息207,第16级,状态1,第7行   列名称“ NAME”无效。

我在这里去哪里?

2 个答案:

答案 0 :(得分:0)

已解决:)

DECLARE
@Cols1  VARCHAR(MAX),
@Cols2  VARCHAR(MAX),
@Query  VARCHAR(MAX),
@Period VARCHAR(MAX) = -12 ; --/ Select number of months to view back on (excluding current month) \--

SELECT 
@Cols1 = STUFF((SELECT DISTINCT ',' +'ISNULL('+ QUOTENAME(CONCAT(DATENAME(MONTH, S.TxDate),' ',YEAR(S.TxDate)))+',0) AS' + QUOTENAME(CONCAT(DATENAME(MONTH, S.TxDate),' ',YEAR(S.TxDate))) 
                FROM _bvSTTransactionsFull AS S
                WHERE S.Module = 'AR' AND S.TxDate > = DATEADD(MONTH, -13, DATEADD(MONTH, DATEDIFF(MONTH, 0, GETDATE()), 0))
                FOR XML PATH (''), TYPE).value('.','NVARCHAR(MAX)'),1,1,'')                     --/ allows the first SELECT fields to have the ISNULL function and Alias \--
SELECT
@Cols2 = STUFF((SELECT DISTINCT ',' + QUOTENAME(CONCAT(DATENAME(MONTH, S.TxDate),' ',YEAR(S.TxDate)))
                FROM _bvSTTransactionsFull AS S
                WHERE S.Module = 'AR' AND S.TxDate > = DATEADD(MONTH, -13, DATEADD(MONTH, DATEDIFF(MONTH, 0, GETDATE()), 0))
                FOR XML PATH (''), TYPE).value('.','NVARCHAR(MAX)'),1,1,'')  --/ becasue of the need for ISNULL above, second @Cols needed for the Pivot (pivot cannot have ISNULL in it) \--

SELECT
   @Query =
'SELECT
Item_Code_Desc,
'+@Cols1+'
FROM
(SELECT
     CONCAT(ST.Code,'' - '', ST.Description_1)                                  AS Item_Code_Desc,
     STT.ActualQuantity                                                         AS Qty,
     CONCAT(DATENAME(MONTH, STT.TxDate),'' '',YEAR(STT.TxDate))                 AS [Period]
 FROM 
     _bvSTTransactionsFull AS STT
 INNER JOIN 
     StkItem AS ST ON STT.AccountLink = ST.StockLink
 WHERE 
     STT.TxDate >= DATEADD(MONTH, '+@Period+', DATEADD(MONTH, DATEDIFF(MONTH, 0, GETDATE()), 0))
     AND STT.Module = ''AR'') AS P
PIVOT  
(SUM(P.Qty)
    FOR P.Period IN ('+@cols2+')
) AS PVT '

PRINT @Query
EXEC (@Query)

答案 1 :(得分:0)

上面的结果是正确的,但是您不会按正确的日期对列进行排序...

以下内容可以满足您的需求:

DECLARE
@Cols1  VARCHAR(MAX),
@Cols2  VARCHAR(MAX),
@Query  VARCHAR(MAX),
@Period VARCHAR(MAX) = -13 ; --/ Select number of months to view back on (excluding current month) \--


declare @tmptbl table (PeriodDate datetime, col1 varchar(100), col2 varchar(100))
insert into @tmptbl (PeriodDate, col1, col2)

SELECT DISTINCT dPeriodDate,'ISNULL('+ QUOTENAME(CONCAT(DATENAME(MONTH, dPeriodDate),' ',YEAR(dPeriodDate)))+',0) AS' + QUOTENAME(CONCAT(DATENAME(MONTH, dPeriodDate),' ',YEAR(dPeriodDate))) col1
,   QUOTENAME(CONCAT(DATENAME(MONTH, dPeriodDate),' ',YEAR(dPeriodDate))) col2
                FROM _bvSTTransactionsFull AS S join _etblPeriod p on EOMONTH(s.TxDate) = p.dPeriodDate
                WHERE S.Module = 'AR' AND S.TxDate > = DATEADD(MONTH, -13, DATEADD(MONTH, DATEDIFF(MONTH, 0, GETDATE()), 0))

SELECT 
@Cols1 = STUFF((SELECT ',' + col1 
                FROM @tmptbl order by PeriodDate
                FOR XML PATH (''), TYPE).value('.','NVARCHAR(MAX)'),1,1,'')                     --/ allows the first SELECT fields to have the ISNULL function and Alias \--
SELECT
@Cols2 = STUFF((SELECT ',' + col2
                FROM @tmptbl order by PeriodDate
                FOR XML PATH (''), TYPE).value('.','NVARCHAR(MAX)'),1,1,'')  --/ becasue of the need for ISNULL above, second @Cols needed for the Pivot (pivot cannot have ISNULL in it) \--

SELECT
   @Query =
'SELECT
Item_Code_Desc,
'+@Cols1+'
FROM
(SELECT
     CONCAT(ST.Code,'' - '', ST.Description_1)                                  AS Item_Code_Desc,
     STT.ActualQuantity                                                         AS Qty,
     CONCAT(DATENAME(MONTH, STT.TxDate),'' '',YEAR(STT.TxDate))                 AS [Period]
 FROM 
     _bvSTTransactionsFull AS STT
 INNER JOIN 
     StkItem AS ST ON STT.AccountLink = ST.StockLink
 WHERE 
     STT.TxDate >= DATEADD(MONTH, '+@Period+', DATEADD(MONTH, DATEDIFF(MONTH, 0, GETDATE()), 0))
     AND STT.Module = ''AR'') AS P
PIVOT  
(SUM(P.Qty)
    FOR P.Period IN ('+@cols2+')
) AS PVT '

PRINT @Query
EXEC (@Query)

我把我所做的更改都用小写字母写给大家,以查看更改...