[英]SQL Join 3 tables with null values
I have a query that returns members, their last visit and their last payment. 我有一个查询,该查询返回成员,他们的最后访问和最后的付款。 My problem is that it doesn't return members without a visit and/or a payment.
我的问题是,没有访问和/或付款,它不会返回会员。
I previously didnt include the last visits and I then had a query with LEFT and RIGHT JOINs instead of INNER but when I added the visit table I received som help to include it but we didn't notice that we were missing the members with null values in visit or payment. 我以前没有包括最后一次访问,然后我用LEFT和RIGHT JOINs而不是INNER进行了查询,但是当我添加访问表时,我得到了som help来包含它,但我们没有注意到我们缺少具有空值的成员造访或付款。
I've tried applying LEFT and RIGHT JOINs without any luck. 我试过应用左和右联接没有任何运气。 I've also tried adding eg.
我也尝试添加例如。 "OR (pt.member_id IS NULL)" also without success.
“ OR(pt.member_id IS NULL)”也没有成功。
SELECT
mr.member_id,
mr.name,
mr.tag,
pt.semester,
pt.date,
vt.date,
FROM
members mr
INNER JOIN
payment pt
ON
pt.member_id = mr.member_id
INNER JOIN
( SELECT
member_id,
MAX(payment_id) max_value
FROM
payment
GROUP BY
member_id ) pt2
ON
pt.member_id = pt2.member_id
AND
pt.payment_id = pt2.max_value
INNER JOIN
visit vt
ON
vt.member_id = mr.member_id
INNER JOIN
( SELECT
member_id,
MAX(date) max_visit_value
FROM
visit
GROUP BY
member_id ) vt2
ON
vt.member_id = vt2.member_id
AND
vt.date = vt2.max_visit_value
I want to get a result where visit and/or payment can be null. 我想得到一个访问和/或付款可以为空的结果。
I hope I make sense and that someone can help me :) 我希望我有道理,希望有人可以帮助我:)
MySQL 5.6 MySQL 5.6
The following version using left joins everywhere might give you the result you want: 以下版本在各处使用左联接可能会为您提供所需的结果:
SELECT
mr.member_id,
mr.name,
mr.tag,
pt.semester,
pt.date,
vt.date,
FROM members mr
LEFT JOIN payment pt
ON pt.member_id = mr.member_id
LEFT JOIN
(
SELECT member_id, MAX(payment_id) max_value
FROM payment
GROUP BY member_id
) pt2
ON pt.member_id = pt2.member_id AND pt.payment_id = pt2.max_value
LEFT JOIN visit vt
ON vt.member_id = mr.member_id
LEFT JOIN
(
SELECT member_id, MAX(date) max_visit_value
FROM visit
GROUP BY member_id
) vt2
ON vt.member_id = vt2.member_id AND vt.date = vt2.max_visit_value;
Correlated subqueries might be the simplest solution: 关联子查询可能是最简单的解决方案:
SELECT mr.member_id, mr.name, mr.tag,
(SELECT pt.semester
FROM payment pt
WHERE pt.member_id = mr.member_id
ORDER BY pt.date DESC
LIMIT 1
) as last_payment_semester
(SELECT pt.date
FROM payment pt
WHERE pt.member_id = mr.member_id
ORDER BY pt.date DESC
LIMIT 1
) as last_payment_date
(SELECT MAX(vt.date,)
FROM visit vt
WHERE vt.member_id = mr.member_id
ORDER BY vt.date DESC
LIMIT 1
) as last_visit_date
FROM members mr;
For performance, you want indexes on payment(member_id, date desc, semester)
and visit(member_id, date desc)
. 为了提高性能,您需要在
payment(member_id, date desc, semester)
和visit(member_id, date desc)
上建立索引。
Admittedly, having to repeat essentially the same subquery twice for the date and the semester is somewhat inelegant. 诚然,在日期和学期中必须重复本质上相同的子查询两次,这有点麻烦。
In MySQL 8+, you can use window functions: 在MySQL 8+中,您可以使用窗口函数:
SELECT mr.member_id, mr.name, mr.tag, pt.semester, pt.date, vt.date
FROM members mr LEFT JOIN
(SELECT pt.*,
ROW_NUMBER() OVER (PARTITION BY pt.member_id ORDER BY pt.date DESC) as seqnum
FROM payment pt
) pt
ON pt.member_id = mr.member_id AND pt.seqnum = 1 LEFT JOIN
(SELECT pt.*,
ROW_NUMBER() OVER (PARTITION BY vt.member_id ORDER BY vt.date DESC) as seqnum
FROM visit vt
) vt
ON vt.member_id = mr.member_id AND vt.seqnum = 1
The biggest problem here is that a member can have many payments and many visits. 这里最大的问题是会员可以进行很多付款和多次访问。 You only want to show the latest of each.
您只想显示每个最新的。 That is easy for the visits, as you only want to show the (maximum) date.
这对于访问很容易,因为您只想显示(最大)日期。 For payments, however, you also want to show the semester belonging to the maximum date.
但是,对于付款,您还想显示属于最长日期的学期。 If the semester is ascending like the date, then it's easy again: Use
MAX(semester)
. 如果学期像日期一样升序,那么这又很容易:使用
MAX(semester)
。 If it isn't, then you must retrieve the maximum date row instead. 如果不是,则必须检索最大日期行 。
As of MySQL 8: 从MySQL 8开始:
SELECT
mr.member_id,
mr.name,
mr.tag,
pt.semester,
pt.date,
vt.date
FROM members mr
LEFT JOIN
(
SELECT
member_id,
semester,
date,
MAX(date) OVER (PARTITION BY member_id) AS last_date
FROM payment
) pt ON pt.member_id = mr.member_id AND pt.dateb = pt.last_date
LEFT JOIN
(
SELECT
member_id,
MAX(date) AS max_visit_value
FROM visit
GROUP BY member_id
) vt ON vt.member_id = mr.member_id
ORDER BY mr.member_id;
In earlier versions: 在早期版本中:
SELECT
mr.member_id,
mr.name,
mr.tag,
pt.semester,
pt.date,
vt.date
FROM members mr
LEFT JOIN
(
SELECT
member_id,
semester,
date
FROM payment
WHERE (member_id, date) IN
(
SELECT member_id, MAX(date)
FROM payment
GROUP BY member_id
)
) pt ON pt.member_id = mr.member_id
LEFT JOIN
(
SELECT
member_id,
MAX(date) AS max_visit_value
FROM visit
GROUP BY member_id
) vt ON vt.member_id = mr.member_id
ORDER BY mr.member_id;
LEFT JOIN
can help if records are more in master table that would surely give you null visits/payments as those ids would not be there in the other joined table. 如果主表中的记录更多,那么
LEFT JOIN
可以提供帮助,因为这些ID在其他联接表中不会出现,因此肯定会给您空访问/付款。 If that isnt the case too try to debug via run subqueries seperately check for are there any null values encountered for visits/payments when run seperately. 如果不是这种情况,也请尝试通过运行子查询单独进行调试,以检查单独运行时是否存在访问/付款遇到的任何空值。
A little tweak on Thorsten Kettner's answer made it work: 稍微调整一下Thorsten Kettner的答案就可以了:
Thanks everyone :) 感谢大家 :)
SELECT
mr.member_id,
mr.name,
mr.tag,
pt.semester,
pt.date,
vt.date
FROM members mr
LEFT JOIN
(
SELECT
member_id,
semester,
date
FROM payment
WHERE ( member_id, date ) IN
(
SELECT
member_id,
MAX(date)
FROM
payment
GROUP BY
member_id
)
) pt ON pt.member_id = mr.member_id
LEFT JOIN
(
SELECT
member_id,
date,
door
FROM visit
WHERE ( member_id, date ) IN
(
SELECT
member_id,
MAX(date)
FROM
visit
GROUP BY
member_id
)
) vt ON vt.member_id = mr.member_id
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.