表-1
订单日期 | 客户编号 | ProductId | 数量 |
---|---|---|---|
2021-03-01 | 1 | 1 | 10 |
2021-03-01 | 1 | 3 | 20 |
2021-03-02 | 1 | 2 | 15 |
2021-03-02 | 1 | 3 | 10 |
2021-03-03 | 1 | 1 | 10 |
2021-03-03 | 1 | 5 | 25 |
此表还包含其他客户的数据以及客户 2、3、4 ...
表-2
ProductId | 产品名称 |
---|---|
1 | P1 |
2 | P2 |
3 | P3 |
4 | P4 |
5 | P5 |
产品不固定,可能会添加P6、P7 ...
结果:
订单日期 | P1 | P2 | P3 | P4 | P5 |
---|---|---|---|---|---|
2021-03-03 | 10 | 25 | |||
2021-03-02 | 15 | 10 | |||
2021-03-01 | 10 | 20 |
我需要这个结果,是否可以使用 Pivot / UnPivot
答案 0 :(得分:0)
是的,可以使用Pivot,但我个人不喜欢Pivot,我使用CASE WHEN 语句代替,因为它更简单且输入更少。如果我没记错的话,使用 CASE WHEN 而不是 Pivot 也没有性能损失。
SELECT
T1.OrderDate,
[P1] = SUM(CASE WHEN T2.ProductName = 'P1' THEN Quantity END),
[P2] = SUM(CASE WHEN T2.ProductName = 'P2' THEN Quantity END),
[P3] = SUM(CASE WHEN T2.ProductName = 'P3' THEN Quantity END),
[P4] = SUM(CASE WHEN T2.ProductName = 'P4' THEN Quantity END),
[P5] = SUM(CASE WHEN T2.ProductName = 'P5' THEN Quantity END)
FROM Table1 T1
JOIN Table2 T2 ON T1.ProductId = T2.ProductID
GROUP BY T1.OrderDate
如果您不使用 SUM() 函数,您的结果中会得到 NULL 值,我建议您尝试一下,这样您就知道为什么需要 SUM() 函数了。
旁注:Pivot 和 CASE WHEN 都没有启用动态列数,您需要为此使用动态 SQL。
答案 1 :(得分:0)
它不是非常漂亮,但您可以使用动态 SQL 从 Erik Blomgren 生成查询:
DECLARE @cols NVARCHAR(MAX), @query NVARCHAR(MAX);
SET @cols = STUFF(
(
SELECT
','+QUOTENAME(ProductName) + '=SUM(CASE ProductId WHEN ' + CAST(ProductId as varchar) + ' THEN Quantity END)'
FROM Table2 FOR XML PATH(''), TYPE
).value('.', 'nvarchar(max)')
, 1, 1, '');
SELECT @query = 'SELECT OrderDate ' + @cols + ' FROM Table1 GROUP BY OrderDate';
EXEC sp_executesql @query
看到我们无论如何都在生成 SQL,实际查询匹配的是 Id,而不是 ProductName,所以我们根本不需要加入这个实例
SELECT OrderDate
,[P1]=SUM(CASE ProductId WHEN 1 THEN Quantity END)
,[P2]=SUM(CASE ProductId WHEN 2 THEN Quantity END)
,[P3]=SUM(CASE ProductId WHEN 3 THEN Quantity END)
,[P4]=SUM(CASE ProductId WHEN 4 THEN Quantity END)
,[P5]=SUM(CASE ProductId WHEN 5 THEN Quantity END)
FROM Table1 GROUP BY OrderDate
您可以同样轻松地使用相同的技术来生成 PIVOT/UNPIVOT 查询,但您明确表示您不想要其中之一;)
答案 2 :(得分:0)
您需要获得的结果可以使用简单的 case 语句或使用 Pivot 和聚合来获得。我个人更喜欢 PIVOT,因为它可以进行各种数据转换,我们可以随心所欲地获取数据。我在这里添加了两种解决方案。
解决方案 01:使用 PIVOT 和稍后聚合结果。这看起来更复杂,因为您需要同时了解 PIVOT 和 Aggregate 函数。
stereoRectify()
解决方案 02:使用简单的 case 语句:
SELECT [B].[OrderDate]
, SUM([B].[P1]) AS [P1]
, SUM([B].[P2]) AS [P2]
, SUM([B].[P3]) AS [P3]
, SUM([B].[P5]) AS [P5]
FROM
(
SELECT [PIVOTED].[OrderDate]
, ISNULL( [PIVOTED].[P1] ,'') AS [P1]
, ISNULL( [PIVOTED].[P2], '') AS [P2]
, ISNULL( [PIVOTED].[P3], '') AS [P3]
, ISNULL( [PIVOTED].[P5], '') AS [P5]
FROM(
SELECT
[T1].[OrderDate],
[T1].[ProductId],
[T2].[ProductName],
[T1].[Quantity]
FROM [TABLE_1] [T1]
INNER JOIN [TABLE_2] [T2]
ON [T1].[ProductId] = [T2].[ProductId]
) P
PIVOT
(
SUM([P].[Quantity])
FOR [P].[ProductName] IN ([P1],[P2],[P3],[P5])
) PIVOTED
) AS B
GROUP BY [B].[OrderDate]
结果 02: Result for Solution 02:
注意:您需要处理添加到表格中的新产品。正如您所看到的,这两种解决方案都对产品名称进行了硬编码,因此您需要对其进行处理。如果您需要更通用的解决方案,请告诉我。我将提供动态 PIVOT,您无需在添加新产品时对其进行处理。
答案 3 :(得分:0)
Here is the dynamic PIVOT for the query
DECLARE @SQL AS VARCHAR(MAX)
, @cols_ AS vARCHAR(MAX)
--Making the column list dynamically
SELECT @cols_ = STUFF((SELECT DISTINCT ', '+QUOTENAME( [T2].[ProductName])
FROM [TABLE_2] [T2]
FOR XML PATH('')), 1, 1, '')
print @cols_
--preparing PIVOT query dynamically.
SET @SQL = ' SELECT
pivoted.*
into #Temp_data
FROM
(
SELECT
[T1].[OrderDate],
[T2].[ProductName],
SUM([T1].[Quantity] ) AS [Quantity]
FROM [TABLE_1] [T1]
INNER JOIN [TABLE_2] [T2]
ON [T1].[ProductId] = [T2].[ProductId]
GROUP BY [T1].[OrderDate],
[T2].[ProductName]
) AS [p]
PIVOT
(
MIN([P].[Quantity])
FOR [P].[ProductName] IN (' + @cols_ + ')
) AS pivoted;
select *
from #Temp_data [B]
-- GROUP BY [B].[OrderDate]
drop table #Temp_data
';
PRINT( @SQL)
EXEC (@SQL)
结果: Dynamic PIVOT