SQL - 根据来自多个 table 的信息对 table 进行排序

SQL - ordering table by information from multiple tables

问题的标题可能不是很清楚 - 我不太确定如何命名这个问题,但我希望我的解释能让我的问题更清楚。

我有 3 个 table:

[1] 得分

id rating_type
1 UPVOTE
2 UPVOTE
3 DOWNVOTE
4 UPVOTE
5 DOWNVOTE
6 DOWNVOTE

[2] post_score

post_id score_id
1 1
1 2
1 3
2 4
2 5
2 6

和[3]post

id title
1 title1
2 title2

我的目标是按分数订购[3]posttable

假设UPVOTE代表值为1,DOWNVOTE代表值为-1;在这个例子中,post where id = 1 有3个分数与之相关,它们的值为UPVOTE,UPVOTE,DOWNVOTE,使得这个post的“数字分数”:2;

同样,post 其中 id = 2,也有 3 个分数,这些值是:UPVOTE、DOWNVOTE、DOWNVOTE,使得“数字分数”:-1;

我如何按这个分数订购 post table?在此示例中,如果我按分数升序排序,我会期望得到以下结果:

id title
2 title2
1 title1

我的尝试没有成功,目前我被困在这个查询中,还没有真正做任何有用的事情:

WITH fullScoreInformation AS (
    SELECT * FROM score s
    JOIN post_score ps ON s.id = ps.score_id),
    upvotes AS (SELECT * FROM fullScoreInformation WHERE rating_type = 'UPVOTE'),
    downvotes AS (SELECT * FROM fullScoreInformation WHERE rating_type = 'DOWNVOTE')
SELECT p.id, rating_type, title FROM post p JOIN fullScoreInformation fsi on p.id = fsi.post_id

我正在使用 PostgreSQL。查询将在我的 Spring 引导应用程序中使用(我通常使用本机查询)。

也许这个数据结构不好,我应该以不同的方式构造我的实体?

My goal is to order post table by score. Assume UPVOTE represents value of 1 and DOWNVOTE value of -1

一个选项使用子查询来计算每个 post:

的赞成票和反对票
select p.*, s.*
from post p
cross join lateral (
    select 
        count(*) filter(where s.rating_type = 'UPVOTE'  ) as cnt_up,
        count(*) filter(where s.rating_type = 'DOWNVOTE') as cnt_down
    from post_score ps
    inner join score s on s.id = ps.score_id
    where ps.post_id = p.id
) s
order by s.cnt_up - s.cnt_down desc

Perhaps this data structure is bad and I should have constructed my entities differently ?

就目前而言,我认为不需要两个不同的 tables post_scorescore。对于您显示的数据,这是 1-1 关系,因此只需一个 table 就足够了,存储 post id 和评级类型。

你最好使用 LEFT 加入,否则你不会得到没有投票的帖子。然后聚合以获得分数的过滤总和。然后将这些总和相加,应用 coalesce() 得到 0 没有投票的帖子并按结果排序。

SELECT p.id,
       p.title
       FROM post p
            LEFT JOIN post_score ps
                      ON ps.post_id = p.id
            LEFT JOIN score s
                      ON s.id = ps.score_id
       GROUP BY p.id,
                p.title
       ORDER BY coalesce(sum(1) FILTER (WHERE rating_type = 'UPVOTE')
                         +
                         sum(-1) FILTER (WHERE rating_type = 'DOWNVOTE'),
                         0);

我同意 GMB 关于多余的评论 table。