在 PostgreSQL 中按多个内连接的条件计数

Posted

技术标签:

【中文标题】在 PostgreSQL 中按多个内连接的条件计数【英文标题】:Count by condition of multiple inner joins in PostgreSQL 【发布时间】:2019-02-22 15:42:53 【问题描述】:

我有以下表格:

UserUserPostViewPost

UserPostView 是一个连接表,其中包含有关User 在查看帖子后是否赞成、反对或通过的附加信息。

Post 有一列 postable_type 指示帖子的类型(TextPostImagePost 等)。

我想计算按postable_type 分组的每个用户的赞成、反对和通过计数。

我当前的查询非常慢,我很确定它可以很容易地进行优化。

SELECT
    U.id,
    count((UP.postable_type = 'text_post' AND UPV.passed = true) OR NULL) as text_posts_pass_count,
    count((UP.postable_type = 'text_post' AND UPV.upvote = true) OR NULL) as text_posts_upvote_count,
    count((UP.postable_type = 'text_post' AND UPV.downvote = true) OR NULL) as text_posts_downvote_count,
    count((UP.postable_type = 'image_post' AND UPV.passed = true) OR NULL) as image_posts_pass_count,
    count((UP.postable_type = 'image_post' AND UPV.upvote = true) OR NULL) as image_posts_upvote_count,
    count((UP.postable_type = 'image_post' AND UPV.downvote = true) OR NULL) as image_posts_downvote_count
FROM
    users U
    INNER JOIN(
        SELECT
            user_id,
            post_id,
            passed,
            upvoted,
            downvoted
        FROM 
            user_post_views
    ) UPV on U.id :: TEXT = UPV.user_id :: TEXT
    INNER JOIN(
        SELECT
            id,
            postable_type
        FROM
            posts
    ) UP on UPV.post_id :: TEXT = UP.id :: TEXT
GROUP BY
    U.id

【问题讨论】:

【参考方案1】:

不要对连接进行类型转换!我想你只需要:

SELECT UPV.user_id,
       COUNT(*) FILTER (WHERE p.postable_type = 'text_post' AND upv.passed) as text_posts_pass_count,
       COUNT(*) FILTER (WHERE p.postable_type = 'text_post' AND upv.upvote) as text_posts_upvote_count,
       COUNT(*) FILTER (WHERE p.postable_type = 'text_post' AND upv.downvote ) as text_posts_downvote_count,
       COUNT(*) FILTER (WHERE p.postable_type = 'image_post' AND upv.passed) as image_posts_pass_count,
       COUNT(*) FILTER (WHERE p.postable_type = 'image_post' AND upv.upvote) as image_posts_upvote_count,
       COUNT(*) FILTER (WHERE p.postable_type = 'image_post' AND upv.downvote) as image_posts_downvote_count
FROM user_post_views upv JOIN
     posts p
     ON upv.post_id = p.id 
GROUP BY upv.user_id;

变化:

不要对连接进行类型转换!这肯定会阻碍优化器。 users 表似乎没有必要。 不需要子查询。 FILTER 比条件聚合稍快。更重要的是,意图更明确。

【讨论】:

谢谢。假设我想从 User 表中获取更多信息,例如 last_session_date... 那你会怎么做? @lightyrs 。 . .然后你会加入它。你的问题没有这样的列。

以上是关于在 PostgreSQL 中按多个内连接的条件计数的主要内容,如果未能解决你的问题,请参考以下文章

在 postgresql 中按级别和 regexp_substr 连接

SQL:按条件从不同表中按计数排序

针对多个条件的不同记录的 SQL 计数

postgresql 在不同条件下计数不同

PostgreSQL 按特定条件分组并计数

具有多个左连接和计数的错误计算(Laravel)