【问题标题】:SQL Server : display distinct list of orders, and indicate which orders contain specific productsSQL Server:显示不同的订单列表,并指示哪些订单包含特定产品
【发布时间】:2018-08-13 08:08:56
【问题描述】:

我有一个包含大量数据的表,但表中的相关数据如下所示:

订单表:

+----------+-----------+---------------+
| OrderID  | Product   |    Date       |
+----------+-----------+---------------+
|    1     | Apple     |  01/01/2001   |
|    1     | Pear      |  01/01/2001   |
|    1     | Pear      |  01/01/2001   |
|    1     | Orange    |  01/01/2001   |
|    1     | Pineapple |  01/01/2001   |
|    2     | Cherry    |  02/02/2002   |
|    2     | Cherry    |  02/02/2002   |
|    3     | Orange    |  03/03/2003   |
|    3     | Apple     |  03/03/2003   |
|    3     | Cherry    |  03/03/2003   |
+----------+-----------+---------------+

我想要一个查询来返回一个不同的订单列表,如果订单包含某些产品,则这样表示:

+----------+-----------+--------+-------+
| OrderID  |   Date    | Apple? | Pear? |
+----------+-----------+--------+-------+
|    1     |01/01/2001 |    X   |   X   |
|    2     |02/02/2002 |        |       |
|    3     |03/03/2003 |    X   |       |
+----------+-----------+--------+-------+

这里是我停下来决定寻求帮助的地方:

WITH CTEOrder AS
(
   SELECT
       OrderID, Product, Date,
       ROW_NUMBER() OVER (PARTITION BY OrderID ORDER BY OrderID ASC) AS OrderRN
   FROM 
       Orders
)
CTEApple as 
(
    SELECT
        OrderID, Product, Date,
        ROW_NUMBER() OVER (PARTITION BY OrderID ORDER BY OrderID ASC) AS AppleRN
    FROM 
        Orders
    WHERE 
        Product = 'Apple'
),
CTEPear
(
    SELECT
        OrderID, Product, Date,
        ROW_NUMBER() OVER (PARTITION BY OrderID ORDER BY OrderID ASC) AS PearRN
    FROM 
        Orders
    WHERE 
        Product = 'Pear'
)
SELECT
    o.OrderID, o.Product, o.Date,
    co.OrderRN, a.AppleRN, p.PearRN
FROM 
    Orders AS o
OUTER JOIN 
    CTEOrder AS co ON o.OrderID = co.Orderid
OUTER JOIN 
    CTEApple AS a ON o.OrderID = a.OrderID
OUTER JOIN 
    CTEPear AS p ON o.OrderID = p.OrderID
WHERE 
    (co.OrderRN IS NULL AND a.AppleRN IS NULL AND p.PearRN IS NULL
     OR co.OrderRN = 1 AND a.AppleRN IS NULL AND p.PearRN IS NULL
     OR co.OrderRN = 1 AND a.AppleRN = 1 AND p.PearRN IS NULL
     OR co.OrderRN = 1 AND a.AppleRN = 1 AND p.PearRN = 1
     OR co.OrderRN = 1 AND a.AppleRN IS NULL AND p.PearRN = 1
     OR co.OrderRN IS NULL AND a.AppleRN = 1 AND p.PearRN IS NULL
     OR co.OrderRN IS NULL AND a.AppleRN = 1 AND p.PearRN = 1
     OR co.OrderRN IS NULL AND a.AppleRN IS NULL AND p.PearRN = 1)

目前我的结果集很笨拙,有大量重复。

我认为我正朝着错误的方向前进,但我不知道 SQL Server 中有哪些其他工具可供我按照我需要的方式切割这些数据。

感谢您的指导!

这是我在 Nik Shenoy 指导下的结果集:

+----------+-----------+----------------+
| OrderID  |    Date   | Apple? | Pear? |
+----------+-----------+----------------+
|    1     | 01/01/2001|    x   |  NULL |
|    1     | 01/01/2001|  NULL  |   x   | 
|    1     | 01/01/2001|  NULL  |   x   |
|    1     | 01/01/2001|  NULL  |  NULL |
|    1     | 01/01/2001|  NULL  |  NULL |
|    2     | 02/02/2002|  NULL  |  NULL |
|    2     | 02/02/2002|  NULL  |  NULL |
|    3     | 03/03/2003|  NULL  |  NULL |
|    3     | 03/03/2003|    x   |  NULL |
|    3     | 03/03/2003|  NULL  |  NULL |
+----------+-----------+----------------+

每个订单只有 1 行的下一步是什么:

+----------+-----------+--------+-------+
| OrderID  |   Date    | Apple? | Pear? |
+----------+-----------+--------+-------+
|    1     |01/01/2001 |    X   |   X   |
|    2     |02/02/2002 |        |       |
|    3     |03/03/2003 |    X   |       |
+----------+-----------+--------+-------+

【问题讨论】:

  • 我对您尝试解决看似简单的问题印象深刻。
  • 该术语是“枢轴”。但是,如果您清楚简洁地说明您在值、列和列名方面所做的事情并在 Google 上搜索,您会遇到很多关键问题和答案。

标签: sql sql-server join common-table-expression outer-join


【解决方案1】:

你可以只使用条件聚合:

select o.orderid, date,
       max(case when product = 'Apple' then 'X' end) as IsApple,
       max(case when product = 'Pear' then 'X' end) as IsPear
from orders o
group by o.orderid, date;

【讨论】:

    【解决方案2】:

    如果您事先知道所有产品,则可以使用 Transact-SQL PIVOT 关系运算符按产品交叉制表数据。如果使用 MAX 或 COUNT,则可以将非 NULL 或非零输出转换为 'x'

    SELECT
        PivotData.OrderID
    ,   PivotData.OrderDate
    ,   CASE WHEN PivotData.Apple IS NULL THEN '' ELSE 'X' END AS [Apple?]
    ,   CASE WHEN PivotData.Pear IS NULL THEN '' ELSE 'X' END AS [Pear?]
    ,   CASE WHEN PivotData.Orange IS NULL THEN '' ELSE 'X' END AS [Orange?]
    ,   CASE WHEN PivotData.Pineapple IS NULL THEN '' ELSE 'X' END AS     [Pineapple?]
    ,   CASE WHEN PivotData.Cherry IS NULL THEN '' ELSE 'X' END AS [Cherry?]
    FROM
        (SELECT OrderID, Product, OrderDate) AS [Order]
    PIVOT   (MAX(Product) FOR Product IN ( [Apple], [Pear], [Orange], [Pineapple], [Cherry] )) AS PivotData
    

    【讨论】:

    • 感谢 Nik Shenoy,这让我快到了!结果集现在列出了所有订单,Pear?/Apple?列在适当的位置有一个“X”,但我也留下了所有的空值。我下一步应该怎么做才能只取回每个订单的 1 行?
    • 我添加了一个子查询。如果 PIVOT 运算符的源表包含其他字段,您可能会看到行重复。如果您减少源表,那应该会消失,您应该会看到每个订单/日期组合有一行。
    • 也许我得到了不同的结果,因为我的源表实际上是连接的产物?在您的指导下,这是我的查询: SELECT OrderID ,Date ,[Apple?] ,[Pear?] FROM ( Select o.OrderID ,o.Date ,o.ProductID .p.ProductName From Orders as O JOIN Product as p on o. ProductID = p.ProductID ) 作为 SourceTable Pivot ( MAX(ProductName) FOR ProductName in ([Apple?], [Pear?]) ) 作为 PivotData
    • 您需要去掉子查询中的“o.ProductID”。这将是每个产品唯一的,因此数据透视表不能仅按 OrderID 和 Date 聚合。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-12-13
    • 1970-01-01
    • 1970-01-01
    • 2021-11-26
    • 2014-05-04
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多