我有三张桌子:
users
、posts
和comments
。
我如何
SELECT
前三个帖子,每个帖子都有评论数和前三个评论?
示例:SQL Fiddle
目标是构建一个如下所示的表格
预期输出:
-- post_id comment_id user_id body created_at
-- 1 4 1 Hello. I'm Jane. August, 28 2016 14:12:01
-- 1 1 2 Nice post, Jane. August, 28 2016 14:12:01
-- 1 2 1 Thank you, John. August, 28 2016 14:12:01
-- 1 3 2 You're welcome. August, 28 2016 14:12:01
-- 2 2 1 This is post 2. August, 28 2016 14:12:01
-- 2 5 2 I like this. August, 28 2016 14:12:01
-- 2 6 1 Why, thank you. August, 28 2016 14:12:01
-- 3 0 1 This is post 3. August, 28 2016 14:12:01
理解预期输出背后的逻辑
您对预期输出有相当复杂的需求。根据我从您的 sql fiddle 中了解到的预期结果,您想要:
comment_id
和 body
逻辑上的差异似乎如下:
对于代表一个post的每一行:
comment_id
中存储该帖子的评论数量user_id
中存储撰写帖子的用户body
中存储帖子正文created_at
中存储创建帖子时的时间戳虽然对于代表 comment 的每一行,逻辑是类似的(但对于评论,而不是帖子),但您要存储评论
comment_id
的 id
列除外。
查询及解释
有关实例,请参阅 SQL fiddle
首先,获取前三个帖子并为它们建立行,计算每个帖子的评论数。然后,将这些帖子行与评论行合并,并使用
row_number()
函数将输出中的评论行限制为每个帖子最多 3 行。
将
0
指定为帖子的行号意味着它们满足 rn <= 3
的条件。
为了按照您的意愿对输出进行排序,以便每个帖子的评论都紧随其后排序,我添加了一个
order_column
以便能够将其包含在 ORDER BY
中。
WITH first_posts AS (
SELECT p.id AS post_id, COUNT(c.id) AS comment_id, p.user_id, p.body, p.created_at
FROM (SELECT * FROM posts ORDER BY id LIMIT 3) AS p
LEFT JOIN comments AS c
ON p.id = c.post_id
GROUP BY 1, 3, 4, 5
)
SELECT post_id, comment_id, user_id, body, created_at
FROM (
SELECT 1 AS type, post_id, comment_id, user_id, body, created_at, 0 AS r
FROM first_posts
UNION ALL
SELECT 2 AS type, p.post_id, c.id, c.user_id, c.body, c.created_at,
ROW_NUMBER() OVER (PARTITION BY p.post_id ORDER BY c.id) AS r
FROM first_posts AS p
INNER JOIN comments AS c
ON p.post_id = c.post_id
ORDER BY post_id, type, comment_id
) AS f
WHERE r <= 3;
您可以使用子查询将您的选择限制为前 3 条帖子,并且
row_number
仅包含每个帖子的前 3 条评论:
SELECT * FROM (
SELECT *,
ROW_NUMBER() OVER (PARTITION BY c.post_id ORDER BY c.id) rn
FROM posts p
JOIN comments c ON c.post_id = p.id
WHERE p.id IN (SELECT id FROM posts ORDER BY id LIMIT 3)
) t WHERE rn <= 3
或者如果您想要每个用户的前 3 个帖子和评论
SELECT * FROM (
SELECT *,
ROW_NUMBER() OVER (PARTITION BY c.post_id ORDER BY c.id) comments_rn,
ROW_NUMBER() OVER (PARTITION BY p.user_id ORDER BY p.id) post_rn
FROM posts p
JOIN comments c ON c.post_id = p.id
JOIN users u ON u.id = p.user_id
) t WHERE comments_rn <= 3 and post_rn <= 3
编辑语法和列名称:
Select id, name, p.*, c.*
from users u
join posts p on p.User_Id = u.Id
and (Select count(*) From posts
where user_Id = u.Id
and created_at <= p.created_at) <= 3
join comments c on c.post_Id = p.Id
and (Select count(*) From comments
where post_Id = p.Id
and created_at <= c.created_at) <= 3