枢轴/反枢轴
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)
我有两个表,一个有状态——这是一个不断变化的列表——所以下周可以添加一个值,例如 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)