SQL 连接 3 个具有空值的表
SQL Join 3 tables with null values
我想查询 return 的成员,他们上次访问和上次付款。我的问题是 return 没有访问 and/or 的会员不会付款。
我之前没有包含上次访问,然后我使用 LEFT 和 RIGHT JOIN 而不是 INNER 进行了查询,但是当我添加访问时 table 我收到了一些帮助以包含它,但我们没有注意到我们在访问或付款中缺少具有空值的成员。
我试过应用 LEFT 和 RIGHT JOIN,但没有任何运气。
我也试过添加例如。 "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
我想获得访问 and/or 付款可以为空的结果。
我希望我说得有道理,希望有人能帮助我 :)
MySQL 5.6
以下版本在任何地方都使用左连接可能会给您想要的结果:
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;
相关子查询可能是最简单的解决方案:
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;
为了提高性能,您需要在 payment(member_id, date desc, semester)
和 visit(member_id, date desc)
上建立索引。
不可否认,必须针对日期和学期重复两次基本相同的子查询有点不雅。
在MySQL 8+中,您可以使用window函数:
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
这里最大的问题是一个会员可以有很多次付款和很多次访问。您只想显示每个的最新版本。这对于访问来说很容易,因为您只想显示(最大)日期。但是,对于付款,您还希望显示属于最大日期的学期。如果学期像日期一样递增,那么就又简单了:使用 MAX(semester)
。如果不是,那么您必须改为检索最大日期 行。
截至 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;
早期版本:
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
可以提供帮助,如果主 table 中的记录更多,那肯定会给你 null visits/payments 因为这些 ID 不会出现在其他加入的 table 中.如果不是这种情况,请尝试通过 运行 子查询进行调试,分别检查当 运行 时 visits/payments 是否遇到任何空值。
对 Thorsten Kettner 的回答稍作调整使其生效:
谢谢大家:)
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
我想查询 return 的成员,他们上次访问和上次付款。我的问题是 return 没有访问 and/or 的会员不会付款。
我之前没有包含上次访问,然后我使用 LEFT 和 RIGHT JOIN 而不是 INNER 进行了查询,但是当我添加访问时 table 我收到了一些帮助以包含它,但我们没有注意到我们在访问或付款中缺少具有空值的成员。
我试过应用 LEFT 和 RIGHT JOIN,但没有任何运气。 我也试过添加例如。 "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
我想获得访问 and/or 付款可以为空的结果。
我希望我说得有道理,希望有人能帮助我 :)
MySQL 5.6
以下版本在任何地方都使用左连接可能会给您想要的结果:
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;
相关子查询可能是最简单的解决方案:
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;
为了提高性能,您需要在 payment(member_id, date desc, semester)
和 visit(member_id, date desc)
上建立索引。
不可否认,必须针对日期和学期重复两次基本相同的子查询有点不雅。
在MySQL 8+中,您可以使用window函数:
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
这里最大的问题是一个会员可以有很多次付款和很多次访问。您只想显示每个的最新版本。这对于访问来说很容易,因为您只想显示(最大)日期。但是,对于付款,您还希望显示属于最大日期的学期。如果学期像日期一样递增,那么就又简单了:使用 MAX(semester)
。如果不是,那么您必须改为检索最大日期 行。
截至 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;
早期版本:
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
可以提供帮助,如果主 table 中的记录更多,那肯定会给你 null visits/payments 因为这些 ID 不会出现在其他加入的 table 中.如果不是这种情况,请尝试通过 运行 子查询进行调试,分别检查当 运行 时 visits/payments 是否遇到任何空值。
对 Thorsten Kettner 的回答稍作调整使其生效:
谢谢大家:)
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