【问题标题】:How to JOIN a 2nd table with condition based on 3rd JOIN table?如何在基于第三个 JOIN 表的条件下加入第二个表?
【发布时间】:2022-01-16 15:14:52
【问题描述】:

我需要使用基于第三个 JOIN 表的 JOIN 条件将 2 个表与第二个表连接起来。

问题是,在加入第二个表的同时,我无法从第三个 JOIN 表中获取值。

View on DB Fiddle

Table A: users
-------
user_id INT PRIMARY
Table B: orders
-------
order_id INT PRIMARY
user_id INT
invoice_id INT
Table C: invoices
-------
invoice_id INT PRIMARY
invoice_status VARCHAR [voided, paid]

这就是我想做的:

SELECT 
    A.user_id,
    B.order_id,
    C.invoice_id,
    C.invoice_status
FROM users A
LEFT JOIN orders B 
    ON (B.user_id = A.user_id
        AND C.invoice_status = 'paid')
LEFT JOIN invoices C
    ON (C.invoice_id = B.invoice_id)

第9行AND C.invoice_status = 'paid')指的是表C还没有join,所以这个查询会导致Error in query (1054): Unknown column 'C.invoice_status' in 'on clause'

我在WHERE 子句中不能有这个条件的原因是因为我仍然想返回所有用户记录,无论他们是否有任何订单或“已付款”发票。所以添加WHERE invoice_status = 'paid' 不会返回没有任何订单的用户和invoice_status = 'voided' 的用户。

另外,当用户有两个订单链接到两个不同的发票记录,但 1 个发票的 invoice_status 是“已付款”,而另一个是“无效”时,我只想返回“已付款”记录。可以有许多 voided 发票,但只有 1 个“已付款”发票记录。

顺便说一句,这是强制执行的:sql_mode=only_full_group_by,所以我不能在 order_idinvoice_id 字段上没有某种聚合或条件的情况下执行 GROUP BY user_id


SELECT 
    A.user_id,
    B.order_id,
    C.invoice_id,
    C.invoice_status
FROM users A
LEFT JOIN orders B 
    ON (B.user_id = A.user_id)
LEFT JOIN invoices C
    ON (C.invoice_id = B.invoice_id);
user_id order_id invoice_id invoice_status
1 1 1 voided
1 2 2 paid
2 3 1 voided
3 NULL NULL NULL

我想要的结果:

user_id order_id invoice_id invoice_status
1 2 2 paid
2 3 1 voided
3 NULL NULL NULL

每个user_id 只能返回一次,当有多个相关订单时,invoice_status = 'paid' 是首选行。


如果有人知道如何实现这一点,请不胜感激。

谢谢!

【问题讨论】:

  • 在您的情况下,您需要使用存储过程。
  • 代替C.invoice_status = 'paid',您可以将NOT EXISTS (...) 添加到ON 子句中为B 排除不需要的行

标签: mysql sql database join group-by


【解决方案1】:

使用ROW_NUMBER()函数并根据user_id对行进行编号并根据invoice_status排序然后获取第一行

SELECT user_id,
       order_id,
       invoice_id,
       invoice_status
FROM
  (SELECT 
    A.user_id,
    B.order_id,
    C.invoice_id,
    C.invoice_status,
    ROW_NUMBER() OVER(PARTITION BY A.user_id ORDER BY C.invoice_status) AS num
  FROM users A
  LEFT JOIN orders B 
    ON (B.user_id = A.user_id)
  LEFT JOIN invoices C
    ON (C.invoice_id = B.invoice_id)) t
WHERE num = 1

db<>fiddle

【讨论】:

    【解决方案2】:

    感谢ProGu 的评论,我可以使用EXISTS 解决它。

    SELECT 
        A.user_id,
        B.order_id,
        C.invoice_id,
        C.invoice_status
    FROM users A
    LEFT JOIN orders B 
        ON B.user_id = A.user_id
        AND EXISTS( SELECT 
                1
            FROM
                invoices
            WHERE
                invoices.invoice_id = B.invoice_id
                    AND invoices.invoice_status = 'paid')
    LEFT JOIN invoices C
        ON C.invoice_id = B.invoice_id
    
    user_id order_id invoice_id invoice_status
    1 2 2 paid
    2 NULL NULL NULL
    3 NULL NULL NULL

    谢谢!

    【讨论】:

      猜你喜欢
      • 2023-03-14
      • 1970-01-01
      • 1970-01-01
      • 2013-03-21
      • 2020-12-16
      • 2023-03-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多