我有一个复杂的PostgreSQL数据库查询,我在构建时遇到了困难。我有两个表:post
表和votes
表。以下是它们的样子:
post
表格 - 我只包含了id
,因为其他列对我的问题并不重要
----
| id |
----
votes
表格vote_type
可以是1
(upvote),-1
(downvote)或0
(中立)。 post_id
是单票的帖子ID的ID。
---- --------- ----------- --------------------------------
| id | post_id | vote_type | timestamp |
---- --------- ----------- --------------------------------
| 1 | 4 | 1 | 2017-03-30 12:17:12.246765-07 |
以下是我要实现的目标:查询过去24小时内投票最多的前10个帖子
我首先构建了以下查询:
SELECT postsTable.*, votesTable.votes
FROM posts AS postsTable
RIGHT JOIN (
SELECT sum(vote_type) votes, post_id
FROM votes
WHERE (extract(day from age(now(), timestamp)) < 1)
GROUP BY post_id)
AS votesTable
ON (postsTable.id = votesTable.post_id)
ORDER BY votes DESC NULLS LAST LIMIT 10;
返回类似的内容:
---- ---------------------- -------
| id | other_colums_between | votes |
---- ---------------------- -------
| 8 | ... | 1 |
它与正确的帖子略有作用但投票栏只显示过去24小时内的投票总数,而不是自帖子发布以来的总票数(这就是我想要的)。原因是因为我只对过去24小时内的投票进行总结,而不是自该职位创建以来的所有投票。
说post
id
8有10票。该查询仅返回1票,因为在过去24小时内只有一个upvote。
因此查询应返回:
---- ---------------------- -------
| id | other_colums_between | votes |
---- ---------------------- -------
| 8 | ... | 10 |
所以我知道我要解决的问题,但我不知道该怎么做。我已经尝试了下面的查询,但这不是我想要的,但我觉得我越来越近了。尽管如此,我还没有在过去24小时内对帖子进行过滤。
SELECT postsTable.*, votesTable.vote_type, extract(day from age(now(), votesTable.timestamp)) age
FROM posts AS postsTable
RIGHT JOIN (SELECT * FROM votes)
AS votesTable ON (postsTable.id = votesTable.post_id)
ORDER BY vote_type DESC NULLS LAST LIMIT 10;
返回:
---- ---------------------- ----------- -----
| id | other_colums_between | vote_type | age |
---- ---------------------- ----------- -----
| 8 | ... | 1 | 3 |
正如您所知,我是SQL的初学者。我还要求我如何简化上面的查询。谢谢你的帮助。
答案 0 :(得分:0)
我可以想到这一点,但我还没有经过考验。
SELECT postsTable.*, votesTable.votes FROM posts AS postsTable RIGHT JOIN ( SELECT sum(vote_type) votes, post_id FROM votes WHERE votes.post_id IN (select unique v.post_id from votes as v where( extract(day from age(now(), timestamp)) < 1) ) GROUP BY post_id) AS votesTable ON (postsTable.id = votesTable.post_id) ORDER BY votes DESC NULLS LAST LIMIT 10;
答案 1 :(得分:0)
请尝试......
SELECT posts.*,
votesTotal AS Votes
FROM posts
JOIN
(
SELECT post_id AS post_id,
SUM( vote_type ) AS votesTotal
FROM votes
WHERE timestamp > NOW() + INTERVAL '-1 day'
GROUP BY post_id
ORDER BY votesTotal DESC
LIMIT 10
) postCounter ON postCounter.post_id = posts.id;
首先,RIGHT JOIN
会将来自Posts
的所有记录与来自子查询的相应记录匹配,而使用JOIN
(也称为{{} {1}})上面我将结果限制在过去24小时内投票的前10个帖子中。如果在过去24小时内有少于10个投票的帖子,那么它只返回该号码。如果您仍然需要10条记录,并且对剩余记录是半随机选择感到满意,那么请将INNER JOIN
更改为JOIN
,并将RIGHT JOIN
添加到外部LIMIT 10
的末尾声明。如果您需要额外的记录但具有特定的排序模式,那么在我可以为其编码之前,您需要指定模式。
其次,SELECT
将在当前日期时间之前24小时生成日期时间。它所属的NOW() + INTERVAL '-1 day'
声明将我们的结果限制为过去24小时内的投票。
如果没有WHERE
,则内部查询将返回GROUP BY
和post_id
的行数,因为有votesTotal
符合post_id
条件的行。 WHERE
(与GROUP BY
一起使用)可以为每个SUM
减少一行。
post_id
为我们提供了由内部查询的其余部分生成的第一个 10条记录。为了确保它们也是 top 10,我确保使用LIMIT 10
对列表进行了排序。
进一步阅读...
http://www.sqlines.com/postgresql/how-to/dateadd
https://www.w3schools.com/sql/sql_groupby.asp
https://www.w3schools.com/sql/sql_join.asp(维恩图特别有帮助)
https://www.w3schools.com/sql/sql_orderby.asp
https://www.postgresql.org/docs/8.1/static/queries-limit.html
如果您有任何问题或意见,请相应发表评论。
答案 2 :(得分:0)
您希望将WHERE子句放在外部表而不是内部表中,因为您希望按日期过滤帖子,而不是投票。
SELECT postsTable.*, votesTable.votes
FROM posts AS postsTable
RIGHT JOIN (
SELECT sum(vote_type) votes, post_id
FROM votes
GROUP BY post_id)
AS votesTable
ON (postsTable.id = votesTable.post_id)
WHERE (extract(day from age(now(), timestamp)) < 1)
ORDER BY votes DESC NULLS LAST LIMIT 10;
(假设您的posts
表还有一个名为timestamp