枢轴/反枢轴

PIVOT / UNPIVOT

我有两个表,一个有状态——这是一个不断变化的列表——所以下周可以添加一个值,例如 4 |推迟:

ID | Status
1  | Open
2  | Closed
3  | Pending

另一个有任务:

ID | Name   | Status ID
1  | Task A | 1
2  | Task B | 1
3  | Task A | 2
4  | Task A | 3
5  | Task C | 2

我想输出每个潜在状态下每个任务(类型)的总和:

Task   | Open | Closed | Pending
Task A | 1    | 1      | 1
Task B | 1    | 0      | 0
Task C | 0    | 1      | 0

我相信 PIVOT 可以将动态行处理成列,但无法将动态 less than dot example 转换为我想要的。

您可以进行条件聚合:

select t.name, 
       sum(case when s.Status = 'Open' then 1 else 0 end) as Open,
       sum(case when s.Status = 'Closed' then 1 else 0 end) as Closed,
       sum(case when s.Status = 'Pending' then 1 else 0 end) as Pending
from status s left join
     tasks t
     on t.StatusID = s.id
group by t.name;

参考此查询[][]

SELECT t2.name
        ,max(CASE 
                WHEN t2.statID = 1
                    THEN 1
                ELSE 0
                END) AS

    OPEN
        ,max(CASE 
                WHEN t2.statID = 2
                    THEN 1
                ELSE 0
                END) AS Closed
        ,max(CASE 
                WHEN t2.statID = 3
                    THEN 1
                ELSE 0
                END) AS pending
    FROM t2
    INNER JOIN t1 ON t1.INT = t2.statID
    GROUP BY t2.name

要管理新状态,您可以使用动态 TSQL:

create table #status([ID] int, [Status] varchar(max))

 insert into #status values
 (1  ,'Open')
,(2  ,'Closed')
,(3  ,'Pending')

create table #task([ID] int, [Name] varchar(max), StatusID int)

insert into #task values
 (1, 'Task A', 1)
,(2, 'Task B', 1)
,(3, 'Task A', 2)
,(4, 'Task A', 3)
,(5, 'Task C', 2)


declare @sql nvarchar(max)='select t.name as [Name]  ' 
select @sql = @sql + ', sum(case when s.Status = ''' + [Status] + ''' then 1 else 0 end) as [' + [Status] + ' ] '

from #status

select @sql = @sql + ' from #status s left join'
select @sql = @sql + '      #task t'
select @sql = @sql + '      on t.StatusID = s.id'
select @sql = @sql + ' group by t.name;'

execute(@sql)

您的数据结果:

再添加 2 个状态(Status4 和 Status5):

create table #status([ID] int, [Status] varchar(max))

 insert into #status values
 (1  ,'Open')
,(2  ,'Closed')
,(3  ,'Pending')
,(4  ,'Status4')
,(5  ,'Status5')

create table #task([ID] int, [Name] varchar(max), StatusID int)

insert into #task values
 (1, 'Task A', 1)
,(2, 'Task B', 1)
,(3, 'Task A', 2)
,(4, 'Task A', 3)
,(5, 'Task C', 2)
,(6, 'Task D', 4)
,(7, 'Task D', 5)


declare @sql nvarchar(max)='select t.name as [Name]  ' 
select @sql = @sql + ', sum(case when s.Status = ''' + [Status] + ''' then 1 else 0 end) as [' + [Status] + ' ] '

from #status

select @sql = @sql + ' from #status s left join'
select @sql = @sql + '      #task t'
select @sql = @sql + '      on t.StatusID = s.id'
select @sql = @sql + ' group by t.name;'

execute(@sql)

结果:

使用 Pivot 试试这个

DECLARE @Table AS TABLE(ID INT, Status VARCHAR(10))
INSERT INTO @Table
SELECT 1,'Open'     UNION ALL
SELECT 2,'Closed'   UNION ALL
SELECT 3,'Pending'

DECLARE @Table2 AS TABLE(ID INT, Name  VARCHAR(10), StatusID VARCHAR(10))
INSERT INTO @Table2

SELECT 1,'Task A',1 UNION ALL
SELECT 2,'Task B',1 UNION ALL
SELECT 3,'Task A',2 UNION ALL
SELECT 4,'Task A',3 UNION ALL
SELECT 5,'Task C',2

;WITH CTE
AS
(
SELECT T1.Name, 
        T1.StatusID,
        t2.[Status] 
FROM @Table2 T1
INNER JOIN @Table T2
 ON t1.StatusID=T2.ID
)
SELECT Name,
       [Open],
       [Closed],
       [Pending]
FROM
(
SELECT * FROM CTE
)AS Src
PIVOT
(
COUNT(StatusID) FOR [Status] IN ([Open],[Closed],[Pending])
) AS PVT

结果

Name    Open Closed Pending
------------------------------
TaskA    1     1         1
TaskB    1     0         0
TaskC    0     1         0

@lojkyelo - 这应该会给你所需的逻辑。基本上你需要一个从状态 table 中提取动态列的数据透视表。然后将使用动态查询传递@PivotColumn。

在此处查看模型 http://rextester.com/FSN2383 并在下方查询:

CREATE TABLE  #Status ([ID] int, [Status] varchar(max))

INSERT INTO #Status 
SELECT 1,'Open' UNION ALL
SELECT 2,'Closed' UNION ALL
SELECT 3,'Pending' UNION ALL
SELECT 4,'Deferred' 

CREATE TABLE  #Task ([ID] int, [Name] varchar(max), StatusID int)
INSERT INTO #Task 
SELECT 1, 'Task A', 1 UNION ALL
SELECT 2, 'Task B', 1 UNION ALL
SELECT 3, 'Task A', 2 UNION ALL
SELECT 4, 'Task A', 3 UNION ALL
SELECT 5, 'Task C', 2 UNION ALL
SELECT 6, 'Task C', 4 



DECLARE @columns NVARCHAR(MAX), @sql NVARCHAR(MAX);
SET @columns = N'';
SELECT @columns += QUOTENAME(Status)+','
    FROM (SELECT p.Status FROM #Status p group by p.Status
    ) AS x;


DECLARE @Pivotcolumns NVARCHAR(MAX)=(select  left (@columns, Len ( @columns) - 1 ))

DECLARE @query NVARCHAR(MAX) = '
      SELECT *
      FROM
      (
            SELECT 
                s.Status,t.Name,StatusID=sum(t.StatusID)
            FROM #Status S
            LEFT JOIN #Task T ON 
                t.StatusID = s.id
            GROUP BY
            s.Status,t.Name

      ) x1
      PIVOT
      (
        COUNT(StatusID)
        for [Status] in ('+ @Pivotcolumns +')
      ) p'

EXEC(@query)