SELECT 个帖子及其评论
SELECT posts and their comments
我有三个 table:users
、posts
和 comments
。
如何 SELECT
前三个 post,每个都有评论数和前三个评论?
示例:SQL Fiddle
目标是打造一个像下面这样的table
- 每个 post_id 分组的第一行是 post
- comment_id是post的评论数
- 下一行是该 post
的前三个评论
预期输出:
-- 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
您可以使用子查询将您的选择限制在前 3 个 post 和 row_number
以仅包含每个 post 的前 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 post 和评论
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
了解预期输出背后的逻辑
您对预期输出有非常复杂的需求。根据我从你的 sql fiddle 中了解到的预期结果,你想要:
- 获得前三个posts
- 获取他们的前三个评论
- 为列
comment_id
和 body
添加具有不同逻辑的 1 和 2 的结果
逻辑上的差异如下:
每行代表一个 post:
- 在
comment_id
中存储该 post 的评论数
- 在
user_id
中存储写了 post 的用户
- 在
body
中存储 post 的正文
- 在
created_at
中存储创建 post 时的时间戳
虽然对于代表 comment 的每一行,逻辑是类比的(但对于评论,而不是 post),但 comment_id
列除外,其中您要存储评论 id
.
查询及说明
有关实际示例,请查看 SQL fiddle
首先,取前三个 post 并为它们建立行,计算每个评论的评论数。然后,将那些 posts 行与评论行合并,并使用 row_number()
函数将输出中的评论行限制为每个 post.
最多 3 个
将 0
指定为 post 的行号意味着它们满足 rn <= 3
.
的条件
为了按照您的意愿对输出进行排序,以便对每个 post 他们的评论进行排序,我添加了一个 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;
我有三个 table:users
、posts
和 comments
。
如何 SELECT
前三个 post,每个都有评论数和前三个评论?
示例:SQL Fiddle
目标是打造一个像下面这样的table
- 每个 post_id 分组的第一行是 post
- comment_id是post的评论数
- 下一行是该 post 的前三个评论
预期输出:
-- 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
您可以使用子查询将您的选择限制在前 3 个 post 和 row_number
以仅包含每个 post 的前 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 post 和评论
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
了解预期输出背后的逻辑
您对预期输出有非常复杂的需求。根据我从你的 sql fiddle 中了解到的预期结果,你想要:
- 获得前三个posts
- 获取他们的前三个评论
- 为列
comment_id
和body
添加具有不同逻辑的 1 和 2 的结果
逻辑上的差异如下:
每行代表一个 post:
- 在
comment_id
中存储该 post 的评论数
- 在
user_id
中存储写了 post 的用户
- 在
body
中存储 post 的正文
- 在
created_at
中存储创建 post 时的时间戳
虽然对于代表 comment 的每一行,逻辑是类比的(但对于评论,而不是 post),但 comment_id
列除外,其中您要存储评论 id
.
查询及说明
有关实际示例,请查看 SQL fiddle
首先,取前三个 post 并为它们建立行,计算每个评论的评论数。然后,将那些 posts 行与评论行合并,并使用 row_number()
函数将输出中的评论行限制为每个 post.
将 0
指定为 post 的行号意味着它们满足 rn <= 3
.
为了按照您的意愿对输出进行排序,以便对每个 post 他们的评论进行排序,我添加了一个 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;