我正在尝试获取具有多个重复组的结果集(将插入到表中)。这是一个脚本,显示了我开始使用的非常简化的数据版本:
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以及更多可能更改的指标,我希望能够使用pivot语句执行此操作,而无需为每个字段明确命名。
这可能吗?谢谢你的任何想法!
答案 0 :(得分: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;
UNPIVOT
获取ThisYearGrossTransactions
,ThisYearGrossPrice
中的列值,
LastYearGrossTransactions
和LastYearGrossPrice
并将它们转换为包含多行的单个列。
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
UNPIVOT
的要求是所有数据类型必须相同,因此您需要将cast
或convert
应用于任何值。然后到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)
两个查询的结果都是一样的。
答案 1 :(得分: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
。 Here is a thread about it on StackOwerflow