代码之家  ›  专栏  ›  技术社区  ›  Nithee

MySQL选择重复的未付款订单,没有对应的已付款订单

  •  2
  • Nithee  · 技术社区  · 7 年前

    我的表结构是:

    命令

    +------+-------------+----------------+-------------+
    | id   | customer_id | payment_status |   created_on| 
    +------+-------------+----------------+-------------+
    | 1    |      1      |      unpaid    | 2018-12-28  |
    | 2    |      1      |      unpaid    | 2018-12-29  |
    | 3    |      2      |      unpaid    | 2018-12-29  |
    | 4    |      2      |      unpaid    | 2018-12-29  |
    | 5    |      4      |      paid      | 2018-12-30  |
    | 6    |      3      |      unpaid    | 2018-12-30  |
    +------+-------------+----------------+-------------+
    

    订购物品

    +------+-----------+-------------+----------+-------+
    | id   | order_id  |  product_id | quantity | price |
    +------+-----------+-------------+----------+-------+
    | 1    |   1       |      4      |  2       | 20.50 |
    | 2    |   1       |      5      |  2       | 25.00 |
    | 3    |   2       |      4      |  2       | 20.50 |
    | 4    |   2       |      5      |  2       | 25.00 |
    | 5    |   3       |      1      |  1       | 20.00 |
    | 6    |   3       |      2      |  1       | 25.00 |
    | 7    |   4       |      1      |  1       | 20.00 |
    | 8    |   4       |      2      |  1       | 25.00 |
    | 9    |   5       |      4      |  2       | 20.50 |
    | 10   |   5       |      5      |  2       | 25.00 |
    | 11   |   6       |      3      |  4       | 15.00 |
    +------+-----------+-------------+----------+-------+
    

    顾客

    +-----+---------------+----------+
    | id  | email         |  name    |
    +-----+---------------+----------+
    | 1   | abc@mail.com  |  user 1  |
    | 2   | xyz@mail.com  |  user 2  |
    | 3   | pqr@mail.com  |  user 3  |
    | 4   | abc@mail.com  |  user 4  |
    +-----+---------------+----------+
    

    Q: 我要的数据是一个客户电子邮件下的订单,该客户的邮件状态为待定,一周内没有支付状态的订单

    预期产量:1 一周内没有对应的付款订单的单笔订单

    +------+-------------+----------------+-------------+
    | id   | customer_id | payment_status |   created_on| 
    +------+-------------+----------------+-------------+
    | 3    |      2      |      unpaid    | 2018-12-29  |
    | 4    |      2      |      unpaid    | 2018-12-29  |
    | 6    |      3      |      unpaid    | 2018-12-30  |
    +------+-------------+----------------+-------------+
    

    Q: 我想要的数据,就好像有2个订单,在一个客户的电子邮件下,有相同的产品和相同的数量,状态为待定,在该客户的电子邮件下,一周内没有支付状态的订单

    预期产量:2 一周内两个订单没有对应的付款订单

    +------+-------------+----------------+-------------+
    | id   | customer_id | payment_status |   created_on| 
    +------+-------------+----------------+-------------+
    | 3    |      2      |      unpaid    | 2018-12-29  |
    | 4    |      2      |      unpaid    | 2018-12-29  |
    +------+-------------+----------------+-------------+
    

    提前谢谢

    2 回复  |  直到 7 年前
        1
  •  2
  •   Rick James diyism    7 年前

    第一个查询是可疑的——你真的是指 email 或 customer_id ? 后者 应该 如何设计模式来区分一个“客户”和另一个“客户”。仔细想想。(并修正数据以使其清晰)同时,我假设 客户id 区分客户。

    我不能把我的头缠在 目的 第一个查询的。你要找的客户支付了以后的订单,但没有支付以前的订单?或者在数据库中查找错误的帖子?不管怎样,这里有一个镜头:

    SELECT  Unpd.id, Unpd.customer_id, Unpd.payment_status, Unpd.created_on
        FROM  Orders AS Pd  ON Pd.customer_id = C.id
          AND  payment_status = 'paid'
        WHERE  NOT EXISTS 
        (
            SELECT  1
                FROM  Orders AS Pd
                WHERE  Pd.customer_id = C.id
                  AND  Pd.payment_status = 'paid'
                  AND  Pd.created_on > NOW() - INTERVAL 1 WEEK 
        ) 
    

    第二个问题。我将其改写为:在同一天找到同一客户的两个(或多个)订单(已付款或未付款)(但不检查项目是否相同):

    SELECT  O2.id, O2.customer_id, O2.payment_status, O2.created_on
        FROM  
        (
            SELECT  O.customer_id, O.created_on
                FROM  Orders AS O
                GROUP BY  O.customer_id, O.created_on
                HAVING  COUNT(*) >= 2
        ) AS MultipleInOneDay
        JOIN  Orders AS O2  USING (customer_id, created_on)
    
        2
  •  2
  •   Arth    7 年前

    我完全同意瑞克的观点

    如果我没看错,现在 customer 表实际上只是添加列 email 和 name 给你的 orders 桌子


    第一季度

    假设您希望在今天的日期和ID字段之后的一周内

    SELECT ou.*
      FROM orders ou /** orders unpaid */
      JOIN customer cu /** customer unpaid */
        ON cu.id = ou.customer_id
     WHERE ou.payment_status = 'unpaid'
       AND NOT EXISTS (
         SELECT 1 
           FROM orders op /** orders paid */
           JOIN customer cp /** customer paid */
             ON cp.id = op.customer_id
          WHERE op.payment_status = 'paid'
            AND op.created_on > CURDATE() - INTERVAL 1 WEEK /** or >= if required */
            AND cp.email = cu.email 
       )
    

    N、 乙。 由于示例中的已付款订单已经超过一周,因此必须调整时间条件才能看到相同的结果


    问题2

    与第一季度相同的假设,加上假设 product_id 每个订单只能出现一次

    SELECT ou.*
      FROM orders ou /** orders unpaid */
      JOIN customer cu /** customer unpaid */
        ON cu.id = ou.customer_id
      JOIN (  
        SELECT GROUP_CONCAT(oudc.id) orders_csv
          FROM (
            SELECT oui.id,
                   cui.email,
                   GROUP_CONCAT(oiui.product_id ORDER BY oiui.product_id) products,
                   GROUP_CONCAT(oiui.quantity ORDER BY oiui.product_id) quantity
              FROM orders oui /** orders unpaid internal */
              JOIN customer cui /** customer unpaid internal */
                ON cui.id = oui.customer_id
              JOIN order_items oiui /** order items unpaid internal */      
                ON oiui.order_id = oui.id
             WHERE oui.payment_status = 'unpaid'   
          GROUP BY oui.id,
                   cui.email
               ) oudc /** orders unpaid dupe check */
      GROUP BY oudc.email, 
               oudc.products, 
               oudc.quantity
        HAVING COUNT(*) = 2 /** or >=2 if required */   
           ) oud /** orders unpaid dupes */
        ON FIND_IN_SET(ou.id, oud.orders_csv) > 0
     WHERE ou.payment_status = 'unpaid'
       AND NOT EXISTS (
         SELECT 1 
           FROM orders op /** orders paid */
           JOIN customer cp /** customer paid */
             ON cp.id = op.customer_id
          WHERE op.payment_status = 'paid'
            AND op.created_on > CURDATE() - INTERVAL 1 WEEK /** or >= if required */
            AND cp.email = cu.email 
       ) 
    

    N、 乙。 由于示例中的已付款订单已经超过一周,因此必须调整时间条件才能看到相同的结果

    这个查询只经过了粗略的测试,可能速度慢得可怜。我建议您单独运行每个嵌套的select查询(从最深处开始)以查看发生了什么。基本上,它将每个订单连接成一行,然后将具有相同电子邮件的重复订单连接成一行,然后使用与Q1类似的逻辑检查此行中的订单

    如果你能有同样的 产品id 每个订单不止一次,您可以使用my orders unpaid dupe check 子查询


    SQLfiddle公司

    我也有 created an SQLfiddle 在示例数据上演示这两个查询。不过,我已经调整了示例订单的日期,以便它们依赖于当前日期