【问题标题】:PIVOT / UNPIVOT枢轴/取消枢轴
【发布时间】:2018-07-26 12:51:38
【问题描述】:

我有两张表,一张有状态 - 这是一个不断变化的列表 - 所以下周可以添加一个值,例如 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 转换为我所追求的。

【问题讨论】:

  • 您是否尝试使用链接到的文章?如果是这样,它可能有助于展示你的尝试以及你在哪里特别挣扎。我会注意到,我在这里看不到任何需要多列的东西。目前还不清楚最终结果中1s 和0s 是什么。那些是唯一可能的值(1 表示“已发生”,0 表示“未发生”)还是它们意味着例如计数?

标签: sql sql-server tsql pivot unpivot


【解决方案1】:

要管理新状态,您可以使用动态 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)

结果:

【讨论】:

    【解决方案2】:

    使用 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
    

    【讨论】:

      【解决方案3】:

      @lojkyelo - 这应该给你你需要的逻辑。基本上,您将需要从状态表中提取动态列的数据透视表。然后将使用动态查询传递@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】:

        你可以做条件聚合:

        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;
        

        【讨论】:

        • 我最初走的是同样的道路,但发现有可能将第四个第五个状态添加到第一个状态表中。
        【解决方案5】:

        参考这个查询[][]

        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
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-06-26
          • 1970-01-01
          • 2010-12-01
          • 2018-11-27
          • 1970-01-01
          相关资源
          最近更新 更多