我怎样才能用 join 编写等效的 sql 查询?
How can i write equivalent sql query with join?
原始sql查询:
SELECT *
FROM
(SELECT p.id,
p.title,
p.mark,
(SELECT max(created)
FROM comments c
WHERE c.post_id=p.id
AND c.mark=1) AS latest_at
FROM posts p) AS Post
WHERE Post.latest_at IS NOT NULL
ORDER BY latest_at DESC LIMIT 10
我正在尝试使用联接编写等效的 sql 查询。我该怎么做?
mysql> describe posts;
+-------------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------------+--------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| user_id | int(11) | NO | | NULL | |
| title | varchar(255) | NO | | NULL | |
| body | text | YES | | NULL | |
| category_id | int(11) | YES | | NULL | |
| tags | varchar(50) | YES | | NULL | |
| mark | tinyint(4) | NO | | 1 | |
| created | datetime | YES | | NULL | |
| modified | datetime | YES | | NULL | |
+-------------+--------------+------+-----+---------+----------------+
mysql> describe comments;
+----------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+----------+--------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| post_id | int(11) | NO | MUL | NULL | |
| name | varchar(255) | NO | | NULL | |
| email | varchar(255) | NO | | NULL | |
| body | varchar(500) | NO | | NULL | |
| mark | tinyint(4) | NO | | 1 | |
| created | datetime | YES | | NULL | |
| modified | datetime | YES | | NULL | |
+----------+--------------+------+-----+---------+----------------+
任何答案将不胜感激。提前致谢。
试试这个:
SELECT p.id, p.title, p.mark,
c.latest_at
FROM posts p
LEFT JOIN (
SELECT post_id, MAX(created) AS latest_at
FROM comments
WHERE mark = 1
GROUP BY post_id
) AS c ON c.post_id = p.id
WHERE c.latest_at IS NOT NULL
ORDER BY c.latest_at DESC LIMIT 10
或者只是这样:
SELECT p.id, p.title, p.mark,
c.latest_at
FROM posts p
INNER JOIN (
SELECT post_id, MAX(created) AS latest_at
FROM comments
WHERE mark = 1
GROUP BY post_id
) AS c ON c.post_id = p.id
ORDER BY c.latest_at DESC LIMIT 10
因为第一个查询的 WHERE
子句的 c.latest_at IS NOT NULL
谓词将 LEFT JOIN
变成了 INNER JOIN
.
我建议:
SELECT p.id,
p.title,
p.mark,
c.latest_at
FROM posts p LEFT OUTER JOIN (select post_id, max(created) latest_at
from comments
where mark=1
group by post_id
) c ON (c.post_id=p.id)
WHERE c.latest_at IS NOT NULL
ORDER BY c.latest_at DESC LIMIT 10;
我看不出有什么理由重写该查询。相关子查询应该有很好的性能。但是,你可以这样做:
SELECT p.id, p.title, p.mark, c.maxc
FROM posts p JOIN
(SELECT post_id, MAX(created) as maxc
FROM comments
WHERE mark = 1
GROUP BY post_id
ORDER BY maxc DESC
LIMIT 10
) c
ON c.post_id = p.id
ORDER BY maxc DESC;
备注:
- 相关子查询现在是聚合查询。
- 这使用
JOIN
而不是 LEFT JOIN
因为(大概)你只想要有评论的行。
LIMIT
在子查询中,所以JOIN
效率更高
我认为常见的 table 表达式也可以(不确定性能):
WITH cte_latest (id, maxCreated)
AS
(
SELECT post_id, MAX(created)
FROM comments
WHERE mark = 1
GROUP BY post_id
)
SELECT * -- Whetever columns you need here
FROM posts p
INNER JOIN cte_latest
ON p.id = cte_latest.id
原始sql查询:
SELECT *
FROM
(SELECT p.id,
p.title,
p.mark,
(SELECT max(created)
FROM comments c
WHERE c.post_id=p.id
AND c.mark=1) AS latest_at
FROM posts p) AS Post
WHERE Post.latest_at IS NOT NULL
ORDER BY latest_at DESC LIMIT 10
我正在尝试使用联接编写等效的 sql 查询。我该怎么做?
mysql> describe posts;
+-------------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------------+--------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| user_id | int(11) | NO | | NULL | |
| title | varchar(255) | NO | | NULL | |
| body | text | YES | | NULL | |
| category_id | int(11) | YES | | NULL | |
| tags | varchar(50) | YES | | NULL | |
| mark | tinyint(4) | NO | | 1 | |
| created | datetime | YES | | NULL | |
| modified | datetime | YES | | NULL | |
+-------------+--------------+------+-----+---------+----------------+
mysql> describe comments;
+----------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+----------+--------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| post_id | int(11) | NO | MUL | NULL | |
| name | varchar(255) | NO | | NULL | |
| email | varchar(255) | NO | | NULL | |
| body | varchar(500) | NO | | NULL | |
| mark | tinyint(4) | NO | | 1 | |
| created | datetime | YES | | NULL | |
| modified | datetime | YES | | NULL | |
+----------+--------------+------+-----+---------+----------------+
任何答案将不胜感激。提前致谢。
试试这个:
SELECT p.id, p.title, p.mark,
c.latest_at
FROM posts p
LEFT JOIN (
SELECT post_id, MAX(created) AS latest_at
FROM comments
WHERE mark = 1
GROUP BY post_id
) AS c ON c.post_id = p.id
WHERE c.latest_at IS NOT NULL
ORDER BY c.latest_at DESC LIMIT 10
或者只是这样:
SELECT p.id, p.title, p.mark,
c.latest_at
FROM posts p
INNER JOIN (
SELECT post_id, MAX(created) AS latest_at
FROM comments
WHERE mark = 1
GROUP BY post_id
) AS c ON c.post_id = p.id
ORDER BY c.latest_at DESC LIMIT 10
因为第一个查询的 WHERE
子句的 c.latest_at IS NOT NULL
谓词将 LEFT JOIN
变成了 INNER JOIN
.
我建议:
SELECT p.id,
p.title,
p.mark,
c.latest_at
FROM posts p LEFT OUTER JOIN (select post_id, max(created) latest_at
from comments
where mark=1
group by post_id
) c ON (c.post_id=p.id)
WHERE c.latest_at IS NOT NULL
ORDER BY c.latest_at DESC LIMIT 10;
我看不出有什么理由重写该查询。相关子查询应该有很好的性能。但是,你可以这样做:
SELECT p.id, p.title, p.mark, c.maxc
FROM posts p JOIN
(SELECT post_id, MAX(created) as maxc
FROM comments
WHERE mark = 1
GROUP BY post_id
ORDER BY maxc DESC
LIMIT 10
) c
ON c.post_id = p.id
ORDER BY maxc DESC;
备注:
- 相关子查询现在是聚合查询。
- 这使用
JOIN
而不是LEFT JOIN
因为(大概)你只想要有评论的行。 LIMIT
在子查询中,所以JOIN
效率更高
我认为常见的 table 表达式也可以(不确定性能):
WITH cte_latest (id, maxCreated)
AS
(
SELECT post_id, MAX(created)
FROM comments
WHERE mark = 1
GROUP BY post_id
)
SELECT * -- Whetever columns you need here
FROM posts p
INNER JOIN cte_latest
ON p.id = cte_latest.id