【问题标题】:Fill in missing values in a SELECT statement在 SELECT 语句中填写缺失值
【发布时间】:2010-04-29 14:16:36
【问题描述】:

我有一个包含两列的表格,即客户 ID 和订单。 假设我的总订单 ID 为 1、2、3、4

所有客户都可以拥有所有四个订单,如下所示:

    1234 1
    1234 2
    1234 3
    1234 4
    3245 3
    3245 4
    5436 2
    5436 4

您可以在上面看到 3245 客户没有订单 ID 1 或 2。 我如何在查询输出中打印:

3245 1
3245 2
5436 1
5436 3

编辑:我没有订单表,但我有一个订单列表,就像我们可以在查询中硬编码一样 (1,2,3,4)。

【问题讨论】:

  • 所以您真正要寻找的是 GAPS(即:那些没有给定订单号的)。您是否有所有客户都应该拥有的订单号主列表?不过听起来不太对劲。因为如果您有一个客户进来一次,但另一个客户进来 100 多次,您不希望每个人都有 100 多个订单。
  • 您是否要查看未链接到这些订单的客户?
  • 这里..一个客户最多只能有 4 个订单,并且没有一个订单会被一个客户做两次。
  • 我主要需要1,2,3,4中没有被他们订购的客户和订单
  • 你有customers 表吗?

标签: sql mysql sql-server oracle


【解决方案1】:
SELECT  c.id, o.order
FROM    (
        SELECT  1 AS order
        UNION ALL
        SELECT  2 AS order
        UNION ALL
        SELECT  3 AS order
        UNION ALL
        SELECT  4 AS order
        ) o
CROSS JOIN
        (
        SELECT  DISTINCT id
        FROM    customer_orders
        ) c
WHERE   NOT EXISTS
        ( 
        SELECT  NULL
        FROM    customer_orders ci
        WHERE   ci.id = c.id
                AND ci.order = o.order
        )

如果你有customers 表,那就更简单了:

SELECT  c.id, o.order
FROM    (
        SELECT  1 AS order
        UNION ALL
        SELECT  2 AS order
        UNION ALL
        SELECT  3 AS order
        UNION ALL
        SELECT  4 AS order
        ) o
CROSS JOIN
        customers c
WHERE   NOT EXISTS
        ( 
        SELECT  NULL
        FROM    customer_orders ci
        WHERE   ci.id = c.id
                AND ci.order = o.order
        )

【讨论】:

  • 优秀。这正是我需要的。BYW 我得到了预期的输出,但你能解释一下查询的 WHERE 部分吗?
  • @benjamin:查询用CROSS JOIN 构建所有可能的客户/订单组合,然后用NOT EXISTS 过滤它们,只返回那些在customer_orders 中没有匹配的。
【解决方案2】:

好的,这里有两个问题。第一个问题是将数字列表转换为行集。有许多不同的方法可以做到这一点,具体取决于您如何将数字输入查询。在下面的示例中,我使用了一个函数,它将逗号分隔的字符串转换为嵌套表,可以使用 TABLE() 函数将其视为常规表。这与您提出的问题并不严格相关。如果您对这部分实现感兴趣,请参阅my post in this other thread

问题的第二部分是为每个客户识别缺失的订单。显而易见的方法(例如对子查询使用 NOT IN)将不起作用,因为 Customer 1234 的订单与所有订单 ID 匹配。我们需要做的是为每个客户填写缺失的订单。这可以通过将 LEFT OUTER JOIN 与 PARTITION BY 子句结合使用来完成。然后通过将 LOJ 查询嵌入到外部 SELECT 中来过滤掉命中是一件简单的事情,如下所示:

SQL> select customer_id
  2         , missing_order_id
  3  from (
  4      select t42.customer_id
  5             , t42.order_id
  6             , nos.column_value as missing_order_id
  7      from  ( select * from table  (str_to_number_tokens('1,2,3,4'))) nos
  8      left outer join t42 partition by ( t42.customer_id )
  9      on nos.column_value = t42.order_id
 10      )
 11  where order_id is null
 12  /

CUSTOMER_ID MISSING_ORDER_ID
----------- ----------------
       3245                1
       3245                2
       5436                1
       5436                3

SQL>

【讨论】:

    【解决方案3】:

    除了我的评论和你现有的表格,我会处理这样的事情......

    select distinct
          a.Customer,
          b.OrderNumber
       from
          YourOrderTable a,
          ( select distinct OrderNumber from YourOrderTable ) b
       where 
          b.OrderNumber NOT IN
              ( select OrderNumber from
                    YourOrderTable c
                    where a.Customer = c.Customer
                      and b.OrderNumber = c.OrderNumber )
    

    通过对 FROM 子句中的第二个表执行 select distinct 并且不对其进行特定连接,您将获得笛卡尔连接...即:对于每个客户,它将连接到每个可能的订单号。

    然后,在您的 WHERE 子句中,NOT IN SQL 测试将只允许“b”。 SQL 子选择中不存在的订单号 (c.)

    这可能是一个非常昂贵的查询,特别是如果您有许多独特的订单..

    【讨论】:

    • 我只有 4 个订单。所以不会有任何成本
    猜你喜欢
    • 2023-02-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-02-24
    • 2019-03-08
    相关资源
    最近更新 更多