简体   繁体   中英

SQL Server 2008 R2 Dynamic Pivot Query with bit types

I have four tables that contain data that used as part of a output that will be defined below

[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)

The desired output format would like this:

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

Notes:

  1. IsFinish would display 0/1
  2. TypeName1, TypeName2, TypeNameN is the text value of [Type].TypeName
  3. Result are filtered to only where [Type].IsWorkflow = 1.
  4. This is running on SQL Server 2008 R2

Here is sample data:

[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

Desired output sample:

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

Notes on output sample:

  1. "Type C" column isn't listed because IsWorkflow = 0
  2. "Type D" column isn't listed because no Tracks have that type

I took a stab at the syntax based on examples I found:

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

There are number of issues with this syntax:

  1. It seems Pivot wants an aggregate summary function, opposed to displaying just displaying value
  2. The column names need to static, wildcard is not supported.

My questions:

  1. Is PIVOT the right choice for what I'm trying to accomplish? If so, how should I update my syntax?
  2. What would be a better approach?

You could do this using a Dynamic Crosstab . See this great article by Jeff Moden for reference.

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)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM