MySQL选择重复的付款待处理订单,没有相应的付款订单

时间:2019-01-02 14:00:12

标签: mysql mysqli

我的表格结构是:

订单

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

order_items

+------+-----------+-------------+----------+-------+
| 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 两个订单,一周内没有相应的付费订单

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

预先感谢

2 个答案:

答案 0 :(得分:2)

第一个查询令人怀疑-您是说email还是customer_id吗?后一种应该是您设计模式以区分一个“客户”和另一个“客户”的方式。仔细考虑一下。 (并修复数据以使其清楚。)同时,我将假设customer_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)

答案 1 :(得分:2)

对于清理架构,我完全同意Rick

如果我没看错,目前您的customer表实际上只是将emailname列添加到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.B。由于距示例中的已付款订单已超过一周,所以您必须调整时间条件才能看到相同的结果


第二季度

与Q1相同的假设,以及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.B。由于距示例中的已付款订单已超过一周,所以您必须调整时间条件才能看到相同的结果

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

如果每个订单可以拥有多个相同的product_id,则可以在我的orders unpaid dupe check子查询中使用进一步的嵌套分组选择进行规范化


SQLfiddle

我也有created an SQLfiddle来演示这两个查询对您的示例数据的作用。但是,我已经调整了示例订单的日期,以便它们取决于当前日期