SQL Server 2008 R2 Dynamic Pivot Query with bit types

SQL Server 2008 R2 Dynamic Pivot Query with bit types

我有四个表,其中包含用作下面定义的输出的一部分的数据

[Status]
StatusId INT
IsFinish BIT

[Type]
TypeId INT
TypeName VARCHAR
IsWorkflow BIT

[System]
SystemId INT
SystemName VARCHAR

[Track]
TrackId INT 
StatusId INT (FK)
TypeId INT (FK)
SystemId INT (FK)

所需的输出格式如下:

SystemName | TypeName1  | TypeName2  | TypeNameN
SystemName | IsFinish   | IsFinish   | IsFinish

备注:

  1. IsFinish 将显示 0/1
  2. TypeName1、TypeName2、TypeNameN 是 [Type].TypeName
  3. 的文本值
  4. 结果仅过滤到 [Type].IsWorkflow = 1 的位置。
  5. 这是 运行 SQL Server 2008 R2

这是示例数据:

[Status]
StatusId, IsFinish
10, 1
11, 1
12, 0

[Type]
TypeId, TypeName, IsWorkflow
101, 'Type A', 1
102, 'Type B', 1
103, 'Type C', 0
104, 'Type D', 1

[System]
SystemId, SystemName
1001, 'System 1'
1002, 'System 2'
1003, 'System 3'


[Track]
TrackId, StatusId, TypeId, SystemId
20001, 10, 101, 1001
20002, 10, 102, 1001
20003, 12, 101, 1002
20004, 11, 101, 1003
20005, 10, 102, 1003
20006, 12, 103, 1003

所需的输出样本:

System Name | Type A  | Type B   
System 1    |   1     |    0    
System 2    |   0     | <NULL>  
System 3    |   1     |    0    

关于输出样本的注释:

  1. "Type C" 列未列出,因为 IsWorkflow = 0
  2. "Type D" 列未列出,因为没有曲目具有该类型

我根据我找到的示例尝试了语法:

SELECT T.*
FROM [Type] T INNER JOIN [Track] TR ON T.TypeId = TR.TypeId 
    INNER JOIN [System] S ON S.SystemId = TR.SystemId 
    INNER JOIN [Status] ST ON ST.StatusId = TR.StatusId
PIVOT ( IsFinish FOR TypeName IN (*)) AS Workflow
WHERE AND IsWorkflow = 1 AND Status = 11

此语法存在多个问题:

  1. Pivot 似乎想要一个聚合汇总函数,而不是仅显示值
  2. 列名需要静态,不支持通配符。

我的问题:

  1. PIVOT 是我想要实现的目标的正确选择吗?如果是这样,我应该如何更新我的语法?
  2. 什么是更好的方法?

您可以使用 Dynamic Crosstab 来完成此操作。请参阅 Jeff Moden 的精彩 article 以供参考。

SQL Fiddle

DECLARE @sql1 VARCHAR(4000) = ''
DECLARE @sql2 VARCHAR(4000) = ''
DECLARE @sql3 VARCHAR(4000) = ''

SELECT @sql1 = 
'SELECT
    s.SystemName' + CHAR(10)

SELECT @sql2 = @sql2 +
' , MAX(CASE WHEN t.TypeId = '+ CONVERT(VARCHAR(5),t.TypeId) + ' THEN CAST(st.IsFinish AS INT) END) AS [' + t.TypeName + '],' + CHAR(10)
FROM(
    SELECT t.*
    FROM Type t
    WHERE
        t.IsWorkflow = 1
        AND EXISTS(SELECT 1 FROM Track WHERE TypeId = t.TypeId)
)t

SELECT @sql3 = 
'FROM System s
INNER JOIN Track t ON t.SystemId = s.SystemId
INNER JOIN Status st ON st.StatusId = t.StatusId
GROUP BY s.SystemName'

PRINT(@sql1 + @sql2 + @sql3)
EXEC(@sql1 + @sql2 + @sql3)