【问题标题】:How do I get sales orders where every line of the sales order is closed?如何获得销售订单的每一行都已关闭的销售订单?
【发布时间】:2012-02-02 06:56:10
【问题描述】:

该表具有“Sales_Order_ID”、“Sales_Order_Line_Number”和“Sales_Order_Line_staus”等字段。我想检索“Sales_Order_ID”,其中“Sales_Order_ID”的每条记录都具有相同的“Sales_Order_Line_Status”。

所以,如果销售订单 X 的每条记录的状态为“已关闭”,那么我想检索它。如果销售订单 Y 有 3 条状态为“已关闭”的记录和一条状态为“打开”的记录,那么我不想检索它。

我试过了:

SELECT DISTINCT s1.so_ID, s1.SO_line_status
FROM sales_order_table s1
INNER JOIN sales_order_table s2
ON s1.so_id = s2.so_id
  AND s1.so_line_status = s2.so_line_status
ORDER BY s1.so_id 

没有成功。以下似乎与我想要的相反:

SELECT DISTINCT s1.so_ID, s1.SO_line_status
FROM sales_order_table s1
INNER JOIN sales_order_table s2
ON s1.so_id = s2.so_id
  AND s1.so_line_status <> s2.so_line_status
ORDER BY s1.so_id  

所以我尝试了:

SELECT DISTINCT s1.so_ID, s1.SO_line_status
FROM sales_order_table s1
INNER JOIN sales_order_table s2
ON s1.so_id = s2.so_id
  AND NOT s1.so_line_status <> s2.so_line_status
ORDER BY s1.so_id

没有成功。

然后我完全是菜鸟,改变了连接类型,只是希望它能起作用。我是接近这里还是完全走错了路?

另外,我意识到上面的查询不会将结果限制为“关闭”状态,但我想如果我能得到一个只返回所有相同状态行的查询,我就可以将它们限制为“关闭”。

抱歉,如果不清楚!如果是这样,我会尽力澄清。

【问题讨论】:

    标签: sql


    【解决方案1】:
    SELECT so_ID
    FROM sales_order_table 
    GROUP BY so_ID
    HAVING MAX(SO_line_status) = 'Closed' AND
           MIN(SO_line_status) = 'Closed' AND
           COUNT(CASE WHEN SO_line_status IS NULL THEN 1 END) = 0
    

    如果您的 RDBMS 支持,您也可以使用 EXCEPT

    SELECT so_ID
    FROM sales_order_table 
    WHERE SO_line_status = 'Closed'
    EXCEPT
    SELECT so_ID
    FROM sales_order_table 
    WHERE SO_line_status IS NULL OR SO_line_status <> 'Closed' 
    

    【讨论】:

    • 可能的边缘情况:如果给定 so_ID 的一个或多个行具有 NULL SO_line_status 并且其余为“已关闭”,则 so_ID 将被错误地返回,因为聚合函数会忽略NULL。
    • HAVING MAX(SO_line_status) = MIN(SO_line_status) 这样的东西怎么样?
    • @MarcusAdams - 因为 OP 对关闭状态特别感兴趣。 “我想如果我能得到一个只返回所有相同状态行的,我就可以将它们限制为‘关闭’。”
    • @Martin,我以为这只是一个例子,但 OP 想要 line_status 相同的任何 ID。
    • @MarcusAdams - 我在上面引用的问题中的一点表明他们只希望将其作为垫脚石(至少对我而言),最终目标是找到所有关闭的地方。 @Joe 边缘情况已修复。
    【解决方案2】:

    这里的基本方法是按 ID 和状态分组。如果该分组的计数等于仅 ID 的计数,那么您将知道所有行具有相同的状态。

    SELECT s1.so_ID, s1.SO_line_status
        FROM sales_order_table s1
        GROUP BY s1.so_ID, s1.SO_Line_status
        HAVING COUNT(*) = (SELECT COUNT(*)
                               FROM sales_order_table s2
                               WHERE s2.so_ID = s1.so_ID)
    

    要将其缩小到“关闭”状态,只需添加一个 WHERE 子句:

    SELECT s1.so_ID, s1.SO_line_status
        FROM sales_order_table s1
        WHERE s1.SO_line_status = 'closed'
        GROUP BY s1.so_ID, s1.SO_Line_status
        HAVING COUNT(*) = (SELECT COUNT(*)
                               FROM sales_order_table s2
                               WHERE s2.so_ID = s1.so_ID)
    

    【讨论】:

      【解决方案3】:

      Joe's approach 绝对可以。以下是一些替代方案(可能更优化也可能更优化):

      反转问题,过滤掉状态为 Open(或 !Closed,取决于您有多少状态)的问题:

      SELECT T1.Id 
      FROM Table as T1
      LEFT JOIN (SELECT Id FROM Table WHERE Status <> 'Closed') as T2 ON
         T1.Id = T2.Id
      WHERE T2.Id IS NULL
      

      使用 MAX 和 MIN 作为分组函数:

      SELECT Id
      FROM Table
      GROUP BY Id, Status
      HAVING MAX(Status) = 'Closed'
      

      使用 2 个派生表:

      SELECT C.Id
      FROM (
         SELECT Id FROM Table WHERE Status = 'Closed'
      ) as C
      LEFT JOIN (
         SELECT Id FROM Table WHERE Status = 'Open'
      ) as O ON
         C.Id = O.Id
      WHERE O.Id IS NULL
      

      我怀疑 2 个 LEFT JOIN 方法会优化得最好,其次是 MAX 版本,然后是 COUNT - 但如果性能对您很重要,您绝对应该配置一下。在没有性能考虑的情况下,我个人认为这 2 个派生表的可读性最高 - 其他人可能不同意。

      【讨论】:

        【解决方案4】:

        您可以使用 ALL 运算符:

        SELECT DISTINCT Sales_Order_ID
        FROM sales_order_table t1
        WHERE
            'Closed' = ALL (
                SELECT Sales_Order_Line_Staus
                FROM sales_order_table t2
                WHERE t1.sales_order_id = t2.sales_order_id
            )
        

        简单地说:选择那些所有关联行都具有相同状态的Sales_Order_IDs,并且该状态恰好是“已关闭”。


        如果您想要任何状态,您可以轻松做到这一点...

        SELECT DISTINCT Sales_Order_ID, Sales_Order_Line_Staus
        FROM sales_order_table t1
        WHERE
            Sales_Order_Line_Staus = ALL (
                SELECT Sales_Order_Line_Staus
                FROM sales_order_table t2
                WHERE t1.sales_order_id = t2.sales_order_id
            )
        

        ...甚至这个(如果您对实际的Sales_Order_Line_Staus 不感兴趣):

        SELECT Sales_Order_ID
        FROM sales_order_table
        GROUP BY Sales_Order_ID
        HAVING COUNT(DISTINCT Sales_Order_Line_Staus) = 1
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2016-01-25
          • 1970-01-01
          • 2021-04-25
          • 2012-07-02
          • 1970-01-01
          相关资源
          最近更新 更多