如何将不同的产品转换为以计数为值的列

How to turn distinct products into columns with the count as value

我有一个 table,其中包含客户 ID 和他们购买的产品:

CustomerId Product
3 Apple
3 Orange
3 Banana
7 Orange
7 Orange
7 Banana
9 Apple
9 Apple
9 Banana

我想为每个客户创建一个列,其中包含他们购买的每个不同值的产品数量:

CustomerId Apple Orange Banana
3 1 1 1
7 0 2 1
9 2 0 1

出于某种原因,我无法在网上找到类似的问题,我怀疑这是由于我无法提出问题。

今天我了解了动态 PIVOT 查询 - 将列转换为行。结合动态查询(其内容直到运行时才完全知道的查询),您可以在不知道列中所有值的情况下使用 PIVOT 查询,方法是在运行时将值添加到查询中。

以我的问题为例:

  1. 创建并填充问题中的第一个 table,我们将其称为销售:

     DROP TABLE IF EXISTS #Sales
     CREATE TABLE #Sales
     (
     CustomerID INT,
     Product      NVARCHAR(255) NOT NULL
     );
     INSERT #Sales VALUES
     (3, N'Apple'),
     (3, N'Orange'),
     (3, N'Banana'),
     (7, N'Orange'),
     (7, N'Orange'),
     (7, N'Banana'),
     (9, N'Apple'),
     (9, N'Apple'),
     (9, N'Banana');
    
  2. 按 CustomerID 和 Product 分组计算每种产品的购买量:

     SELECT CustomerID
            , Product
            , COUNT(*) as Total_bought
     INTO #SalesSummed
     FROM #Sales
     GROUP BY CustomerID, Product
    
  3. 将每个不同的产品添加到数据透视查询:

     DECLARE @columns NVARCHAR(MAX), @sql NVARCHAR(MAX);
     SET @columns = N'';
     SELECT @columns += N', p.' + QUOTENAME(Product)
     FROM (SELECT p.Product FROM #SalesSummed AS p
     GROUP BY p.Product) AS x;
     SET @sql = N'
     SELECT p.CustomerID, ' + STUFF(@columns, 1, 2, '') + '
     INTO #SalesMatrix
     FROM
     (
         SELECT p.CustomerID, p.Product, p.Total_bought
         FROM #SalesSummed AS p
     ) AS j
     PIVOT
     (
         SUM(Total_bought) FOR Product IN ('
         + STUFF(REPLACE(@columns, ', p.[', ',['), 1, 1, '')
         + ')
     ) AS p;';
     PRINT @sql;
     EXEC sp_executesql @sql;
    

第 3 步产生 table SalesMatrix:

CustomerID Apple Banana Orange
3 1 1 1
7 NULL 1 2
9 2 1 NULL

这正是我们想要的(我们可以用 0 替换 NULL)!