SQL Server:显示不同的订单列表,并指明哪些订单包含特定产品

时间:2018-03-05 15:53:20

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

我有一个包含大量数据的表,但表中的相关数据看起来像这样:

订单表:

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

我的下一步是每个订单只有一行:

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

2 个答案:

答案 0 :(得分: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;

答案 1 :(得分:0)

如果您事先了解所有产品,则可以使用Transact-SQL PIVOT关系运算符按产品交叉制表数据。如果您使用MAX或COUNT,您只需将非NULL或非ZERO输出转换为' 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