透视SQL表与动态年份列

时间:2016-03-04 15:39:39

标签: sql sql-server pivot

我无法搞清楚这一点。我检查了类似的帖子,但他们只有一列作为一行旋转。虽然我需要转动

我有以下查询:

SELECT  
      Year([Date]) as Year
      ,SUM([Drop]) as [Drop]
      ,SUM([TicketsDistributed]) as [TicketsDistributed]
      ,SUM([TicketsSold]) as [TicketsSold]
      ,SUM([GrossTickets]) as [GrossTickets]
      ,SUM([GrossTickets])/SUM(TicketsSold) as 'Per Cap'
  FROM [dbo].[Tickets]
  group by [Date]

这给了我这个结果:

Year    Drop    TicketsDistributed  TicketsSold GrossTickets    Per Cap
2016    222          100                 5000     4000.00       0.800000
2015    222          110                 5000     4000.00       0.900000
2014    222          120                 5000     4000.00       1.00000

我想要以下内容:

                       2016   2015   2014   
Drop                   222    222    222    
TicketsDistributed     100    110    120    
TicketsSold            5000   5000   5000     
GrossTickets           4000   4000   4000
Per Cap                0.8     0.9   1

根据建议的答案,这是我到目前为止所做的,但它不起作用

DECLARE @cols AS NVARCHAR(MAX),
    @query  AS NVARCHAR(MAX)

select @cols = STUFF((SELECT ',' + QUOTENAME(Year(Date)) 
                    from [dbo].[SpringTrainings] t
                    cross apply
                    (
                        select    SUM([Drop]) as [Drop]
      ,SUM([TicketsDistributed]) as [TicketsDistributed]
      ,SUM([TicketsSold]) as [TicketsSold]
      ,SUM([GrossTickets]) as [GrossTickets]
      ,SUM([GrossTickets])/SUM(TicketsSold) as PerCap
  FROM [dbo].[SpringTrainings]
                    ) c ([Drop],[TicketsDistributed],[TicketsSold],[GrossTickets],PerCap)
                    group by Year(Date)
                    order by Year(Date)
            FOR XML PATH(''), TYPE
            ).value('.', 'NVARCHAR(MAX)') 
        ,1,1,'')




set @query = 'SELECT [Drop],[TicketsDistributed],[TicketsSold],[GrossTickets],PerCap,' + @cols + ' 
            from 
            (
                select SUM([Drop]) as [Drop]
      ,SUM([TicketsDistributed]) as [TicketsDistributed]
      ,SUM([TicketsSold]) as [TicketsSold]
      ,SUM([GrossTickets]) as [GrossTickets]
      ,SUM([GrossTickets])/SUM(TicketsSold) as PerCap
        FROM [dbo].[SpringTrainings]

            ) x
            pivot 
            (
                max(Year([Date]))
                for Year([Date]) in (' + @cols + ')
            ) p '

execute sp_executesql @query;

1 个答案:

答案 0 :(得分:1)

如果您希望继续在T-SQL中使用pivot操作符,则首先需要“取消”现有查询,以便拥有Year,Label和Value。虽然在T-SQL中有一个univot操作员,我发现使用CROSS APPLY和VALUES要简单得多,同样快一些(对于Brad Schultz的方法read this article更多),我特别喜欢它,因为我可以想象通过布局值对的方式很容易得到结果。

SELECT
      d.Year
    , a.label
    , a.value
FROM (
      SELECT
            YEAR([Date]) AS [Year]
          , SUM([Drop]) AS [Drop]
          , SUM([TicketsDistributed]) AS [TicketsDistributed]
          , SUM([TicketsSold]) AS [TicketsSold]
          , SUM([GrossTickets]) AS [GrossTickets]
          , SUM([GrossTickets]) / SUM(TicketsSold) AS [PerCap]
      FROM [dbo].[Tickets]
      GROUP BY
            [Year]
      ) AS t
      CROSS APPLY ( /* now transform into 5 rows per year but just 1 value column */
          VALUES
                 ('Drop',t.Drop)
               , ('TicketsDistributed',t.TicketsDistributed)
               , ('TicketsSold',t.TicketsSold)
               , ('GrossTickets',t.GrossTickets)
               , ('PerCap',t.PerCap)
      ) AS a (label, value)

该查询(上面)替换了动态SQL中的派生表x。一旦数据被按摩到该形式,枢轴看起来就更简单了:

       ) x
        pivot 
        (
            max([x.Value])
            for [x.Year] in ([2014],[2015],[2016])
        ) p

对于你的@cols,我建议这样简单:

SELECT DISTINCT
    QUOTENAME(Year([date])) 
FROM [dbo].[Tickets]

提示:如果您需要一种订购行的方式,请在交叉申请中加入,如下所示:

      CROSS APPLY ( /* now transform into 5 rows per year but just 1 value column */
          VALUES
                 (1, 'Drop',t.Drop)
               , (2, 'TicketsDistributed',t.TicketsDistributed)
               , (3, 'TicketsSold',t.TicketsSold)
               , (4, 'GrossTickets',t.GrossTickets)
               , (5, 'PerCap',t.PerCap)
      ) AS a (row_order, label, value)

然后在执行透视后可以使用[row_order]。

所以总体看起来像这样:

DECLARE @cols AS nvarchar(max)
      , @query AS nvarchar(max)

SELECT @cols = STUFF((
            SELECT DISTINCT
                  ',' + QUOTENAME(YEAR([date]))
            FROM [dbo].[Tickets]
            FOR xml PATH (''), TYPE
      )
      .value('.', 'NVARCHAR(MAX)')
      , 1, 1, '')


SET @query = 'SELECT [Year], [Label], '
            + @cols 
            + ' FROM (
                  SELECT
                        d.Year
                      , a.label
                      , a.value
                  FROM (
                        SELECT
                              YEAR([Date]) AS [Year]
                            , SUM([Drop]) AS [Drop]
                            , SUM([TicketsDistributed]) AS [TicketsDistributed]
                            , SUM([TicketsSold]) AS [TicketsSold]
                            , SUM([GrossTickets]) AS [GrossTickets]
                            , SUM([GrossTickets]) / SUM(TicketsSold) AS [PerCap]
                        FROM [dbo].[Tickets]
                        GROUP BY
                              [Year]
                  ) AS d
                        CROSS APPLY (
                                  VALUES
                                         (1,''Drop'',t.Drop)
                                       , (2,''TicketsDistributed'',t.TicketsDistributed)
                                       , (3,''TicketsSold'',t.TicketsSold)
                                       , (4,''GrossTickets'',t.GrossTickets)
                                       , (5,''PerCap'',t.PerCap)
                        ) AS a (row_order,label,value)
                ) x
            pivot 
            (
                max([x.Value])
                for [x.Year] in (' + @cols + ')
            ) p
            ORDER BY [row_order]'

EXECUTE sp_executesql @query;