【问题标题】:Dynamic Pivot Table across multiple columns跨多列的动态数据透视表
【发布时间】:2023-03-14 10:41:02
【问题描述】:

我是一个相当新的 SQL,可以使用一些帮助。我有一个时间表数据表,每行都有一个单独的时间表。每个考勤表都有一个包含 jobcode1 到 jobcode16 的列,其中存储了一个指示作业代码的字符串。每一个都有对应的 TotalJob1 到 TotalJob16。

我已经设法在 JobCode1 上创建了一个数据透视,每个 Job 的列和 TotalJob1 的总数都没有问题。我使用this 构建它。

DECLARE @DynamicPivotQuery AS NVARCHAR(MAX)
DECLARE @ColumnName AS NVARCHAR(MAX)

SELECT @ColumnName = ISNULL(@ColumnName + ',','') + QUOTENAME(TS_Job1Code)
FROM (SELECT DISTINCT TS_Job1Code FROM 
dbo.timesheetData) as timesheetdata

SET @DynamicPivotQuery = 
N'SELECT VolumeID, ' + @ColumnName + '
FROM dbo.timesheetData
PIVOT(SUM(TS_TotalJob1)
FOR TS_Job1Code IN (' + @ColumnName + ')) AS PVTTable'

EXEC sp_executesql @DynamicPivotQuery

我正在努力迭代其他 Job 列并将它们合并到一个大数据透视表中,并希望有人能给我指点?

我的想法是尝试重复该步骤 16 次,但我认为这甚至不是正确的方法。

DECLARE @DynamicPivotQuery AS NVARCHAR(MAX)
DECLARE @ColumnName AS NVARCHAR(MAX)
DECLARE @N AS INT
DECLARE @NCHAR AS NVARCHAR(MAX)
SET @N = 1

WHILE @N < 17
BEGIN
SET @NCHAR = CAST(@N as VARCHAR)
SELECT @ColumnName = ISNULL(@ColumnName + ',','') + QUOTENAME(('TS_Job' + 
@NCHAR + 'Code'))
FROM (SELECT DISTINCT ('TS_Job' + @NCHAR + 'Code') FROM 
dbo.timesheetData) as timesheetdata

SET @DynamicPivotQuery = 
N'SELECT ' + @ColumnName + '
FROM dbo.timesheetData
PIVOT(SUM(TS_TotalJob' + @NCHAR + ')
    FOR TS_Job' + @NCHAR + 'Code IN (' + @ColumnName + ')) AS PVTTable'

EXEC sp_executesql @DynamicPivotQuery
SET @N = @N + 1
END
EXEC sp_executesql @SQL

原创

+-------------+----------+----------+----------+-----------+-----------+-----------+
| TimesheetID | JobCode1 | JobCode2 | JobCode3 | TotalJob1 | TotalJob2 | TotalJob3 |
+-------------+----------+----------+----------+-----------+-----------+-----------+
| 1           | J1       | J3       |          | 10        | 9         |           |
+-------------+----------+----------+----------+-----------+-----------+-----------+
| 2           | J2       | J1       | J3       | 5         | 5         | 5         |
+-------------+----------+----------+----------+-----------+-----------+-----------+
| 3           | J2       |          |          | 6         | 3         | 1         |
+-------------+----------+----------+----------+-----------+-----------+-----------+

我想要达到的目标

+-------------+----+----+----+----+----+
| TimesheetID | J1 | J2 | J3 | J4 | J6 |
+-------------+----+----+----+----+----+
| 1           | 10 |    | 9  |    |    |
+-------------+----+----+----+----+----+
| 2           | 5  | 5  | 5  |    |    |
+-------------+----+----+----+----+----+
| 3           |    | 6  |    | 3  | 1  |
+-------------+----+----+----+----+----+

【问题讨论】:

  • 你想要的结果是什么?
  • 要么硬编码 16 次,要么您需要创建一个 cursor 选择所有列名称 TS_Job1Code, TS_Job2Code etc 并在光标正文中创建 dynamic SQL query。就性能而言,它并没有那么糟糕,因为它只会迭代 16 次,并且您只会使用游标 来创建 动态 SQL。
  • 在查询中有 16 个PIVOT,另一方面,需要检查它在您的情况下的性能。 我不确定您是否无法通过其他方式实现您所需要的。
  • @TabAlleman 我已经修改了原始问题。感谢回复

标签: sql sql-server tsql dynamic pivot


【解决方案1】:

这会变得非常复杂,但您可以做的一件事是 UNPIVOT 您的数据,使其看起来像这样:

TimesheetId    JobCode    JobTotal
1              J1         10
1              J3         9
2              J1         5
....

然后 PIVOT 派生表以获得您想要的结果。

【讨论】:

  • 太棒了!谢谢,这对我有用。再次感谢您抽出宝贵时间回复,非常感谢。
【解决方案2】:

就像提到的 Tab 一样,您可以先对数据进行反透视,然后再对其进行透视。

您可以使用 CROSS APPLY 和 VALUES 将您的表还原为临时表。

SELECT ca.* 
INTO #temp
FROM timesheet
CROSS APPLY (VALUES
    (TimesheetID, JobCode1, TotalJob1), 
    (TimesheetID, JobCode2, TotalJob2), 
    (TimesheetID, JobCode3, TotalJob3)
) ca(TimesheetID, JobCode, TotalJob)

这会给你一个类似的表格

TimesheetID JobCode TotalJob
----------- ------- -----------
1           J1      10
1           J3      9
1           NULL    NULL
2           J2      5
2           J1      5
2           J3      5
3           J2      6
3           NULL    3
3           NULL    1

不确定实际数据中是否有空作业代码。但您可以使用上面的Where ca.JobCode IS NOT NULL 消除它们

然后你从临时表中创建你的动态列字符串

DECLARE @JobCodes nvarchar(MAX)
SELECT  @JobCodes = COALESCE(@JobCodes + ',','') + QUOTENAME(JobCode)
FROM       #temp
GROUP BY JobCode
ORDER BY JobCode

然后构建您的动态支点。无需创建全局临时表,只需在您的数据透视查询中使用之前的相同查询即可。

DECLARE @Sql nvarchar(max)
SET @Sql = N'
    SELECT TimeSheetID,' + @JobCodes 
    + 'FROM (
       SELECT ca.* 
       FROM timesheet
       CROSS APPLY (VALUES
          (TimesheetID, JobCode1, TotalJob1), 
          (TimesheetID, JobCode2, TotalJob2), 
          (TimesheetID, JobCode3, TotalJob3)
       ) ca(TimesheetID, JobCode, TotalJob)
    ) t
    PIVOT (
       SUM(TotalJob)
       FOR JobCode IN (' + @JobCodes + ')
    ) p'

EXEC sp_executesql @Sql

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2022-01-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-02-15
    • 1970-01-01
    相关资源
    最近更新 更多