【问题标题】:SQL - ordering table by information from multiple tablesSQL - 按来自多个表的信息排序表
【发布时间】:2021-04-07 18:32:20
【问题描述】:

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

我有 3 张桌子:

[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] 发布

id title
1 title1
2 title2

我的目标是按分数排序 [3] 发布表。

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

同样,id = 2 的帖子也有 3 个分数,这些值是:UPVOTE、DOWNVOTE、DOWNVOTE,得出“数字分数”:-1;

我将如何按此分数排序帖子表?在这个例子中,如果我按分数 asc 排序,我会得到以下结果:

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 Boot 应用程序中使用(我通常使用本机查询)。

也许这个数据结构很糟糕,我应该以不同的方式构建我的实体?

【问题讨论】:

    标签: sql postgresql subquery sql-order-by lateral-join


    【解决方案1】:

    我的目标是按分数排序后表。假设 UPVOTE 表示值为 1,DOWNVOTE 值为 -1

    一个选项使用子查询来计算每个帖子的赞成票和反对票:

    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
    

    也许这个数据结构很糟糕,我应该以不同的方式构建我的实体?

    就目前而言,我认为不需要两个不同的表 post_scorescore。对于您展示的数据,这是一个 1-1 的关系,因此只需一张表就足够了,存储帖子 ID 和评分类型。

    【讨论】:

    • 我可能无法理解某些内容,因为您的查询无法按原样工作 - 我必须删除顶部的 x.* 并将 where ps.post_id = p 更改为 where ps.post_id = p.id - 否则我会出错。但是,通过这些更改,它可以完美运行
    【解决方案2】:

    您最好使用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 关于多余桌子的评论。

    【讨论】:

    • 多余表的原因是因为我也使用相同的系统为 cmets。他们可以以与帖子相同的方式得分。我当前的表格:score、post_score、comment_score。这会改变什么吗?还是表格仍然是多余的?
    • score 表是多余的,是的(除非您没有显示更多内容)。而不是post_score 中的score_id 列,您可以只拥有一个直接存储它是赞成票还是反对票的列(甚至直接存储1 或-1)。对于 cmets 和他们的分数,这是模拟的。
    猜你喜欢
    • 1970-01-01
    • 2018-05-09
    • 2019-01-17
    • 1970-01-01
    • 2021-02-19
    • 2019-01-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多