如何使用 LEFT JOIN 并根据计数将结果限制为一行
How to use LEFT JOIN and limit result to one row based on a count
假设我有 3 tables:
Table 'post'
id
title
0
titleA
1
titleB
2
titleC
Table 'comment'
id
id_post
text
0
1
blaa
1
3
blbb
2
5
blcc
Table 'like'
id
id_comment
vote
0
1
+1
1
5
-1
2
5
+1
我需要获得 post 条评论最多的列表。
查询应该对每个post的每个评论的table“喜欢”(非真实姓名)的投票列(+1,-1 ...)求和,保留higest 加到对应的post.
例如:
post_id
post_title
comment_id
comment_text
like_vote
0
titleA
12
blaaaa
51
1
titleB
25
blabbb
98
2
titleC
63
blaccc
14
$statement = $this->pdo->prepare('SELECT SQL_NO_CACHE p.id AS post_id, p.title AS post_title, c.id AS comment_id, c.text AS comment_text, IFNULL(like.like_vote, 0) AS like_vote FROM post p
LEFT JOIN (SELECT * FROM comment) c ON p.id = c.id_post
LEFT JOIN (SELECT id_comment, IFNULL(SUM(vote), 0) AS like_vote, FROM like GROUP BY id_comment ORDER BY like_vote DESC) like ON c.id = like.id_comment
ORDER BY p.id ASC
');
我得到的结果是,当 post 有 2 条评论时,我得到 2 post 每条评论和计数如下:
post_id: 0, comment_id: 1, like_vote: 5
post_id: 0, comment_id: 2, like_vote: 7
post_id: 1, comment_id: 3, like_vote: 10
post_id: 1, comment_id: 4, like_vote: 3
...
每条评论都得到正确的赞数,但我不知道如何只保留最高评论并避免多行 post 具有相同的 id,像这样:
post_id: 0, comment_id: 2, like_vote: 7
post_id: 1, comment_id: 3, like_vote: 10
如果你能帮助我构建查询那就太好了,我只是找不到它...
编辑:(table 赞的名称只是一个例子,以保持清楚)
你可以写这个查询,你会得到预期的结果。
我只是将 table like 重命名为 comment_like 因为 like 是预定义的词,所以使用预定义的词不是好的做法。
SELECT p.id AS post_id, p.title AS post_title, c.id AS comment_id, c.text AS comment_text, IFNULL(comment_like.like_vote, 0) AS like_vote FROM post p
LEFT JOIN comment c ON p.id = c.id_post
LEFT JOIN (SELECT id_comment, IFNULL(SUM(vote), 0) AS like_vote FROM comment_like GROUP BY id_comment ORDER BY like_vote DESC) comment_like ON c.id = comment_like.id_comment ORDER BY p.id ASC;
一种方法是使用 CTE。使用 ROW_NUMBER() OVER(...) 按 post 和最大票数对结果进行排序和排名。然后拿最大的那个,即where votes_rank = 1
post_id
comment_id
like_votes
votes_rank
0
1
5
1
0
2
7
2
1
4
3
1
1
3
10
2
SQL (MySQL 8.x)
注意 - 使用 table 名称 comment_likes
以避免必须转义关键字 like
WITH cte AS (
SELECT p.id AS post_id
, c.id AS comment_id
, l.like_votes
, ROW_NUMBER() OVER(
PARTITION BY p.id
ORDER BY l.like_votes DESC
) AS votes_rank
FROM post p
LEFT JOIN comment c ON c.id_post = p.id
LEFT JOIN (
SELECT id_comment, SUM(vote) AS like_votes
FROM comment_likes
GROUP BY id_comment
)
l ON l.id_comment = c.id
)
SELECT *
FROM cte
WHERE votes_rank = 1
AND like_votes IS NOT NULL
ORDER BY post_id, like_votes
结果:
post_id
comment_id
like_votes
votes_rank
0
2
7
1
1
3
10
1
db<>fiddle here
更新 2022-04-01
MySQL 5.x 不支持 window 函数,因此您必须求助于子查询。这样的事情应该会产生类似的结果
SELECT p.id AS post_id
, ( SELECT c.id AS comment_id
FROM comment c INNER JOIN comment_likes l ON l.id_comment = c.id
WHERE c.id_post = p.id
GROUP BY c.id
ORDER BY SUM(vote) DESC
LIMIT 1
) AS comment_id
, ( SELECT SUM(l.vote)
FROM comment c INNER JOIN comment_likes l ON l.id_comment = c.id
WHERE p.id = c.id_post
GROUP BY c.id
ORDER BY SUM(l.vote) DESC
LIMIT 1
) AS total_like_votes
FROM post p
HAVING total_like_votes IS NOT NULL
结果:
post_id
comment_id
total_like_votes
0
2
7
1
3
10
db<>fiddle here
假设我有 3 tables:
Table 'post'
id | title |
---|---|
0 | titleA |
1 | titleB |
2 | titleC |
Table 'comment'
id | id_post | text |
---|---|---|
0 | 1 | blaa |
1 | 3 | blbb |
2 | 5 | blcc |
Table 'like'
id | id_comment | vote |
---|---|---|
0 | 1 | +1 |
1 | 5 | -1 |
2 | 5 | +1 |
我需要获得 post 条评论最多的列表。
查询应该对每个post的每个评论的table“喜欢”(非真实姓名)的投票列(+1,-1 ...)求和,保留higest 加到对应的post.
例如:
post_id | post_title | comment_id | comment_text | like_vote |
---|---|---|---|---|
0 | titleA | 12 | blaaaa | 51 |
1 | titleB | 25 | blabbb | 98 |
2 | titleC | 63 | blaccc | 14 |
$statement = $this->pdo->prepare('SELECT SQL_NO_CACHE p.id AS post_id, p.title AS post_title, c.id AS comment_id, c.text AS comment_text, IFNULL(like.like_vote, 0) AS like_vote FROM post p
LEFT JOIN (SELECT * FROM comment) c ON p.id = c.id_post
LEFT JOIN (SELECT id_comment, IFNULL(SUM(vote), 0) AS like_vote, FROM like GROUP BY id_comment ORDER BY like_vote DESC) like ON c.id = like.id_comment
ORDER BY p.id ASC
');
我得到的结果是,当 post 有 2 条评论时,我得到 2 post 每条评论和计数如下:
post_id: 0, comment_id: 1, like_vote: 5
post_id: 0, comment_id: 2, like_vote: 7
post_id: 1, comment_id: 3, like_vote: 10
post_id: 1, comment_id: 4, like_vote: 3
...
每条评论都得到正确的赞数,但我不知道如何只保留最高评论并避免多行 post 具有相同的 id,像这样:
post_id: 0, comment_id: 2, like_vote: 7
post_id: 1, comment_id: 3, like_vote: 10
如果你能帮助我构建查询那就太好了,我只是找不到它...
编辑:(table 赞的名称只是一个例子,以保持清楚)
你可以写这个查询,你会得到预期的结果。
我只是将 table like 重命名为 comment_like 因为 like 是预定义的词,所以使用预定义的词不是好的做法。
SELECT p.id AS post_id, p.title AS post_title, c.id AS comment_id, c.text AS comment_text, IFNULL(comment_like.like_vote, 0) AS like_vote FROM post p
LEFT JOIN comment c ON p.id = c.id_post
LEFT JOIN (SELECT id_comment, IFNULL(SUM(vote), 0) AS like_vote FROM comment_like GROUP BY id_comment ORDER BY like_vote DESC) comment_like ON c.id = comment_like.id_comment ORDER BY p.id ASC;
一种方法是使用 CTE。使用 ROW_NUMBER() OVER(...) 按 post 和最大票数对结果进行排序和排名。然后拿最大的那个,即where votes_rank = 1
post_id | comment_id | like_votes | votes_rank |
---|---|---|---|
0 | 1 | 5 | 1 |
0 | 2 | 7 | 2 |
1 | 4 | 3 | 1 |
1 | 3 | 10 | 2 |
SQL (MySQL 8.x)
注意 - 使用 table 名称 comment_likes
以避免必须转义关键字 like
WITH cte AS (
SELECT p.id AS post_id
, c.id AS comment_id
, l.like_votes
, ROW_NUMBER() OVER(
PARTITION BY p.id
ORDER BY l.like_votes DESC
) AS votes_rank
FROM post p
LEFT JOIN comment c ON c.id_post = p.id
LEFT JOIN (
SELECT id_comment, SUM(vote) AS like_votes
FROM comment_likes
GROUP BY id_comment
)
l ON l.id_comment = c.id
)
SELECT *
FROM cte
WHERE votes_rank = 1
AND like_votes IS NOT NULL
ORDER BY post_id, like_votes
结果:
post_id | comment_id | like_votes | votes_rank |
---|---|---|---|
0 | 2 | 7 | 1 |
1 | 3 | 10 | 1 |
db<>fiddle here
更新 2022-04-01
MySQL 5.x 不支持 window 函数,因此您必须求助于子查询。这样的事情应该会产生类似的结果
SELECT p.id AS post_id
, ( SELECT c.id AS comment_id
FROM comment c INNER JOIN comment_likes l ON l.id_comment = c.id
WHERE c.id_post = p.id
GROUP BY c.id
ORDER BY SUM(vote) DESC
LIMIT 1
) AS comment_id
, ( SELECT SUM(l.vote)
FROM comment c INNER JOIN comment_likes l ON l.id_comment = c.id
WHERE p.id = c.id_post
GROUP BY c.id
ORDER BY SUM(l.vote) DESC
LIMIT 1
) AS total_like_votes
FROM post p
HAVING total_like_votes IS NOT NULL
结果:
post_id | comment_id | total_like_votes |
---|---|---|
0 | 2 | 7 |
1 | 3 | 10 |
db<>fiddle here