使用数据透视表中的值动态创建表列

时间:2019-06-25 17:06:14

标签: sql tsql sql-server-2008-r2

我有一个利用数据透视功能的动态查询,以下是表中数据的示例。

Status 1  | Week 1 |25
Status 1  | Week 1 |25
Status 1  | Week 2 |25
Status 2  | Week 1 | 2
Status 2  | Week 1 | 8
Status 2  | Week 1 | 10
Status 2  | Week 1 | 10 

这是如何返回数据的示例。

            Week 1        Week 2    
Status 1 |    50            25
Status 2      10            20

对于我的查询,我要传递一周的时间,因此我希望接下来的5周为例,因此,例如,如果传递1,我希望从第1周到第6周都有列。 为了方便起见,我编写了以下查询。

--EXEC usp_weekReport @weeks=1, @year='2019'
ALTER PROC usp_weekReport
(
@weeks INT,
@year NVARCHAR(4)

)
AS
DECLARE @columns NVARCHAR(MAX), @sql NVARCHAR(MAX), @csql NVARCHAR(MAX);
SET @columns = N'';
SELECT @columns += N', p.' + QUOTENAME([week]) 
  FROM (
  SELECT p.[week] 
  FROM [Housing_support_DB].[dbo].[Invoices] P 
  WHERE DATEPART(YEAR,P.date)='2019'--@year
  AND 
  ([week] IN (1)
  OR
  [week] IN (1+1)
    OR
  [week] IN (1+2)
    OR
  [week] IN (1+3)
    OR
  [week] IN (1+4)
    OR
  [week] IN (1+5) 
  )
  GROUP BY P.[week] 

  ) AS x;
SET @sql = N'
SELECT p.[statusName],' + STUFF(@columns, 1, 2, '') + '
FROM
(
  SELECT 
    SUM(CAST(REPLACE(REPLACE(A.amount,'','',''''),''$'','''') AS FLOAT)) as sumInvoice,
  A.invoiceStatusID_FK,
  B.statusName,
--  C.programme,
  [week]
  FROM [dbo].[Invoices] A
  INNER JOIN invoiceStatus B
  ON A.invoiceStatusID_FK=B.invoiceStatusID
--  INNER JOIN CapitalAccountBalances C
 -- ON C.accountBalanceID=A.accountBalanceID_FK 
 -- WHERE A.accountBalanceID_FK=5
 GROUP BY invoiceStatusID_FK,B.statusName,[week]--,C.programme
) AS j
PIVOT
(
  SUM(sumInvoice) FOR [week] IN ('
  + STUFF(REPLACE(@columns, ', p.[', ',['), 1, 1, '')
  + ')
) AS p;';
--PRINT @sql;
EXEC sp_executesql @sql;
--SET @csql = N'
--CREATE TABLE ##reportResult
--(
--statusName nvarchar(50),'+
CREATE TABLE ##reportResult
(
statusName nvarchar(50),
weekA INT DEFAULT 0,
 weekB int DEFAULT 0--,
--weekC int DEFAULT 0,
--weekD int DEFAULT 0,
--weekE int DEFAULT 0,
--weekF int DEFAULT 0
)
 INSERT  into  ##reportResult Exec(@sql)
--INSERT ##reportResult Exec(@sql)
--SELECT statusName, weekA,weekB,weekC,weekD,weekE,weekF -- here you have "static SELECT with field names"
--FROM ##reportResult 
--DROP TABLE ##reportResult

问题

我这里遇到的最大问题是,我需要将此查询的结果发送到tempTable ...#reportResult。结果,我需要创建表。但是,如果我尝试使用预期的最大列数(6)创建表,则会收到无效的列数错误。例如,在我的数据库中,我只有两周,这就是为什么我只能创建带有weekA和weekB列的表的原因。我也无法选择。

当前,我正在尝试找到一种方法,该方法可以根据数据透视表第一部分的星期数动态创建表。或者,要操作枢轴的第一部分以在运行时选择Week,week + 1等作为列,这样,我可以创建包含所有字段的列。

感谢所有可以提供的帮助。

1 个答案:

答案 0 :(得分:0)

您需要使用动态SQL,因为需要根据输入星期数生成列名。下面,我为您提供了使用CTE与示例数据一起创建的脚本。您只需要根据表和要求更新脚本即可。

  

您可以测试更改Week_No值的代码

     

对于您的最终查询,只需在删除CTE代码后使用SELECT部分​​

DECLARE @Week_No INT = 2
DECLARE @Loop_Count INT = 1
DECLARE @Column_List VARCHAR(MAX) = '[Week '+CAST(@Week_No AS VARCHAR) +']'

WHILE @Loop_Count < 5
BEGIN
    SET @Column_List = @Column_List +',[Week '+CAST(@Week_No+@Loop_Count AS VARCHAR) +']'
    SET @Loop_Count = @Loop_Count + 1
END

--SELECT @Column_List
EXEC
('
    WITH your_table(Status,Week_No,Val)
    AS
    (
    SELECT ''Status 1'',''Week 1'',25 UNION ALL
    SELECT ''Status 1'',''Week 1'',25 UNION ALL
    SELECT ''Status 1'',''Week 2'',25 UNION ALL
    SELECT ''Status 2'',''Week 1'',2 UNION ALL
    SELECT ''Status 2'',''Week 1'',8 UNION ALL
    SELECT ''Status 2'',''Week 1'',10 UNION ALL
    SELECT ''Status 2'',''Week 1'',10 
    )


    SELECT * FROM
    (
        SELECT * FROM your_table
    ) AS P
    PIVOT
    (
        SUM(val)
        FOR Week_No IN ('+@Column_List+')
    )PVT
')