需要帮助构建 SQL 查询

时间:2021-03-02 13:43:10

标签: sql sql-server select

表-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

4 个答案:

答案 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()

结果: Result for Solution 01:

解决方案 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