3

我正在尝试获取具有多个重复组的结果集(将插入到表中)。这是一个脚本,显示了我开始使用的数据的一个非常简化的版本:

CREATE TABLE #Aggregate(
    StoreKey int ,
    NumberOfDaysBack int ,
    ThisYearGrossTransactions int ,
    ThisYearGrossPrice money ,
    LastYearGrossTransactions int ,
    LastYearGrossPrice money 
) 
GO
INSERT #Aggregate VALUES (10134, 7, 198, 71324.3600, 248, 95889.6089)
INSERT #Aggregate VALUES (10131, 7, 9, 1299.8300, 3, 662.5700)
INSERT #Aggregate VALUES (10132, 7, 57, 11029.5300, 56, 6848.3800)
INSERT #Aggregate VALUES (10130, 7, 6, 429.3100, 15, 1606.1100)
INSERT #Aggregate VALUES (10134, 28, 815, 339315.9265, 822, 342834.2365)
INSERT #Aggregate VALUES (10131, 28, 29, 5725.4900, 8, 1938.4100)
INSERT #Aggregate VALUES (10132, 28, 262, 42892.5476, 269, 37229.2600)
INSERT #Aggregate VALUES (10130, 28, 62, 6427.7072, 93, 13428.0000)

然后我想为每组 NumberOfDaysBack 显示单独的数据集,如下所示:

StoreKey    ThisYearLast7GrossTransactions ThisYearLast7GrossPrice LastYearLast7GrossTransactions LastYearLast7GrossPrice ThisYearLast28GrossTransactions ThisYearLast28GrossPrice LastYearLast28GrossTransactions LastYearLast28GrossPrice
----------- ------------------------------ ----------------------- ------------------------------ ----------------------- ------------------------------- ------------------------ ------------------------------- ------------------------
10130       6                              429.31                  15                             1606.11                 62                              6427.7072                93                              13428.00
10131       9                              1299.83                 3                              662.57                  29                              5725.49                  8                               1938.41
10132       57                             11029.53                56                             6848.38                 262                             42892.5476               269                             37229.26
10134       198                            71324.36                248                            95889.6089              815                             339315.9265              822                             342834.2365

我能够通过此查询获得上述结果集。

-- (using this Common Table expression as a shortcut, there's actually a dimention table
;with Store as (select distinct StoreKey from #Aggregate)
Select
    Store.StoreKey
    ,ThisYearLast7GrossTransactions = DaysBack7.ThisYearGrossTransactions
    ,ThisYearLast7GrossPrice = DaysBack7.ThisYearGrossPrice
    ,LastYearLast7GrossTransactions = DaysBack7.LastYearGrossTransactions
    ,LastYearLast7GrossPrice = DaysBack7.LastYearGrossPrice
    ,ThisYearLast28GrossTransactions = DaysBack28.ThisYearGrossTransactions
    ,ThisYearLast28GrossPrice = DaysBack28.ThisYearGrossPrice
    ,LastYearLast28GrossTransactions = DaysBack28.LastYearGrossTransactions
    ,LastYearLast28GrossPrice = DaysBack28.LastYearGrossPrice    
from Store 
    join #Aggregate DaysBack7
        on Store .StoreKey = DaysBack7.StoreKey
        and DaysBack7 .NumberOfDaysBack = 7
    join #Aggregate DaysBack28
        on Store .StoreKey = DaysBack28.StoreKey
        and DaysBack28 .NumberOfDaysBack = 28
order by Store.StoreKey

但是,由于我的实际数据集要复杂得多,有更多 NumberOfDaysBack 和更多可能更改的指标,我希望能够使用数据透视语句来执行此操作,而无需显式命名每个字段。

这可能吗?感谢您的任何想法!

4

2 回答 2

4

UNPIVOT您可以同时使用和获得您想要的结果PIVOT

select *
from
(
  select storekey, 
    value, col +'Last'+ cast(numberofdaysback as varchar(20)) + 'Days' new_col
  from
  (
    select storekey,
      numberofdaysback,
      cast(ThisYearGrossTransactions as decimal(20,5)) ThisYearGrossTransactions,
      cast(ThisYearGrossPrice as decimal(20,5)) ThisYearGrossPrice,
      cast(LastYearGrossTransactions as decimal(20,5)) LastYearGrossTransactions,
      cast(LastYearGrossPrice as decimal(20,5)) LastYearGrossPrice    
    from aggregate
  ) un
  unpivot
  (
    value
    for col in (ThisYearGrossTransactions, ThisYearGrossPrice,
                LastYearGrossTransactions, LastYearGrossPrice)
  ) unpiv
) src
pivot
(
  sum(value)
  for new_col in ([ThisYearGrossTransactionsLast7Days], [ThisYearGrossPriceLast7Days],
                  [LastYearGrossTransactionsLast7Days], [LastYearGrossPriceLast7Days],
                  [ThisYearGrossTransactionsLast28Days], [ThisYearGrossPriceLast28Days],
                  [LastYearGrossTransactionsLast28Days], [LastYearGrossPriceLast28Days])
) piv;

请参阅带有演示的 SQL Fiddle

获取、 和 中的UNPIVOT列值ThisYearGrossTransactions,并将它们转换为具有多行的单列。ThisYearGrossPriceLastYearGrossTransactionsLastYearGrossPrice

select storekey, 
  value, col +'Last'+ cast(numberofdaysback as varchar(20)) + 'Days' new_col
from
(
  select storekey,
    numberofdaysback,
    cast(ThisYearGrossTransactions as decimal(20,5)) ThisYearGrossTransactions,
    cast(ThisYearGrossPrice as decimal(20,5)) ThisYearGrossPrice,
    cast(LastYearGrossTransactions as decimal(20,5)) LastYearGrossTransactions,
    cast(LastYearGrossPrice as decimal(20,5)) LastYearGrossPrice    
  from aggregate
) un
unpivot
(
  value
  for col in (ThisYearGrossTransactions, ThisYearGrossPrice,
              LastYearGrossTransactions, LastYearGrossPrice)
) unpiv

请参阅带有演示的 SQL Fiddle

的要求UNPIVOT是所有数据类型必须相同,因此您需要应用其中一个castconvert任何值。然后对数据,我通过添加到每条记录来PIVOT创建新的列名。numberofdaysback这些是在PIVOT查询部分中使用的值。

最终结果是:

| STOREKEY | THISYEARGROSSTRANSACTIONSLAST7DAYS | THISYEARGROSSPRICELAST7DAYS | LASTYEARGROSSTRANSACTIONSLAST7DAYS | LASTYEARGROSSPRICELAST7DAYS | THISYEARGROSSTRANSACTIONSLAST28DAYS | THISYEARGROSSPRICELAST28DAYS | LASTYEARGROSSTRANSACTIONSLAST28DAYS | LASTYEARGROSSPRICELAST28DAYS |
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|    10130 |                                  6 |                      429.31 |                                 15 |                     1606.11 |                                  62 |                    6427.7072 |                                  93 |                        13428 |
|    10131 |                                  9 |                     1299.83 |                                  3 |                      662.57 |                                  29 |                      5725.49 |                                   8 |                      1938.41 |
|    10132 |                                 57 |                    11029.53 |                                 56 |                     6848.38 |                                 262 |                   42892.5476 |                                 269 |                     37229.26 |
|    10134 |                                198 |                    71324.36 |                                248 |                  95889.6089 |                                 815 |                  339315.9265 |                                 822 |                  342834.2365 |

如果您有已知数量的值,则上面的静态版本效果很好,NumberOfDaysBack但如果您有未知数量的值,那么您可以使用它的动态版本:

DECLARE @colsUnpivot AS NVARCHAR(MAX),
    @query  AS NVARCHAR(MAX),
    @colsPivot as  NVARCHAR(MAX)

select @colsUnpivot = stuff((select ','+quotename(C.name)
         from sys.columns as C
         where C.object_id = object_id('Aggregate') and
               C.name not in ('StoreKey', 'NumberOfDaysBack')
         for xml path('')), 1, 1, '')

select @colsPivot = STUFF((SELECT  ',' 
                      + quotename(c.name +'Last'
                         + cast(a.NumberOfDaysBack as varchar(10)) +'Days')
                    from Aggregate a
                    cross apply sys.columns  C
                   where C.object_id = object_id('Aggregate') and
                         C.name not in ('StoreKey', 'NumberOfDaysBack')
                   group by c.name, a.NumberOfDaysBack
            FOR XML PATH(''), TYPE
            ).value('.', 'NVARCHAR(MAX)') 
        ,1,1,'')

set @query 
  = 'select *
      from
      (
        select storekey, 
            value, col +''Last''+ cast(numberofdaysback as varchar(20)) + ''Days'' new_col
        from 
        (
          select storekey,
            numberofdaysback,
            cast(ThisYearGrossTransactions as decimal(20,5)) ThisYearGrossTransactions,
            cast(ThisYearGrossPrice as decimal(20,5)) ThisYearGrossPrice,
            cast(LastYearGrossTransactions as decimal(20,5)) LastYearGrossTransactions,
            cast(LastYearGrossPrice as decimal(20,5)) LastYearGrossPrice    
          from aggregate
        ) x
        unpivot
        (
          value
          for col in ('+ @colsunpivot +')
        ) u
      ) x1
      pivot
      (
        sum(value)
        for new_col in ('+ @colspivot +')
      ) p'

exec(@query)

请参阅带有演示的 SQL Fiddle

两个查询的结果将相同。

于 2012-11-20T10:43:49.960 回答
1

您想要达到的结果可能是使用 PIVOT 的结果:

SELECT StoreKey, 
[1] AS ThisYearGrossTransactionsFor7Days, 
[2] AS ThisYearGrossPriceFor7Days, 
[3] AS LastYearGrossTransactionsFor7Days, 
[4] AS LastYearGrossPriceFor7Days, 
[5] AS ThisYearGrossTransactionsFor28Days, 
[6] AS ThisYearGrossPriceFor28Days, 
[7] AS LastYearGrossTransactionsFor28Days, 
[8] AS LastYearGrossPriceFor28Days
FROM
(SELECT StoreKey,ThisYearGrossTransactions AS Value, 1 AS TypeOfAggregate
FROM #Aggregate WHERE NumberOfDaysBack = 7
UNION ALL 
SELECT StoreKey,ThisYearGrossPrice AS Value, 2 AS TypeOfAggregate
FROM #Aggregate WHERE NumberOfDaysBack = 7
UNION ALL 
SELECT StoreKey,LastYearGrossTransactions AS Value, 3 AS TypeOfAggregate
FROM #Aggregate WHERE NumberOfDaysBack = 7
UNION ALL 
SELECT StoreKey,LastYearGrossPrice AS Value, 4 AS TypeOfAggreagate
FROM #Aggregate WHERE NumberOfDaysBack = 7
UNION ALL
SELECT StoreKey,ThisYearGrossTransactions AS Value, 5 AS TypeOfAggregate
FROM #Aggregate WHERE NumberOfDaysBack = 28
UNION ALL 
SELECT StoreKey,ThisYearGrossPrice AS Value, 6 AS TypeOfAggregate
FROM #Aggregate WHERE NumberOfDaysBack = 28
UNION ALL 
SELECT StoreKey,LastYearGrossTransactions AS Value, 7 AS TypeOfAggregate
FROM #Aggregate WHERE NumberOfDaysBack = 28
UNION ALL 
SELECT StoreKey,LastYearGrossPrice AS Value, 8 AS TypeOfAggregate
FROM #Aggregate WHERE NumberOfDaysBack = 28) p
PIVOT(
SUM(Value)
FOR TypeOfAggregate IN ([1], [2], [3], [4], [5], [6], [7], [8])
) AS pvt
ORDER BY StoreKey

为此,如您所见,仍然需要将 转换#Aggregate为不同的格式,并“键入”值(TypeOfAggregate)。

但为此,您可以编写一个Dynamic PIVOT. 这是 StackOwerflow 上关于它的一个线程

于 2012-11-19T13:21:05.703 回答