当聚合来自多个内部查询的数据时,如何避免冗长和简化?

When aggregating data from multiple inner queries, how to avoid the verbosity and simplify?

前提是你有三张表(用户、评论、点赞)

SELECT *
FROM user u
JOIN (SELECT user_id, count(*) as likes
    FROM likes l
    WHERE l.created_on > '2021-10-01' AND l.created_on <= '2021-10-31'
    GROUP BY l.user_id
) as likes ON u.id = likes.user_id
JOIN (
    SELECT user_id, count(*) as comments
    FROM comment c
    WHERE c.created_on > '2021-10-01' AND c.created_on <= '2021-10-31'
) as comments ON u.id = comments.user_id;

有什么方法可以简化这样的查询吗? created_on 过滤器日期是否可以声明为变量?

PL/pgSQL 支持函数内部的变量,因此您可以根据需要将其设为函数,然后查询函数结果。像这样说:

CREATE FUNCTION get_user_interaction_counts
(
   date_start date,
   date_end date
)
RETURNS TABLE(user_id int, like_count int, comment_count int) as $$
SELECT u.id, likes.likes, comments.comments
FROM "user" u
JOIN (SELECT user_id, count(*) as likes
    FROM likes l
    WHERE l.created_on > date_start AND l.created_on <= date_end
    GROUP BY l.user_id
) as likes ON u.id = likes.user_id
JOIN (
    SELECT user_id, count(*) as comments
    FROM comment c
    WHERE c.created_on > date_start AND c.created_on <= date_end
    GROUP BY c.user_id
) as comments ON u.id = comments.user_id

$$ LANGUAGE SQL;

然后你会查询它:

select * from get_user_interaction_counts('2021-10-01', '2021-10-30')

当然这可能不是您想要的。如果您在“仅查询”时需要变量,则取决于您使用的客户端。如果您使用的是 psql,it does support variables。其他客户可能支持也可能不支持,视情况而定。

您还可以做的是稍微修改一下查询,像这样,在开头使用参数 CTE,然后使用它来连接所选参数:

WITH parameters AS (
  SELECT '2021-10-01'::date as date_start
       , '2021-10-30'::date as date_end
)
SELECT u.id, likes.likes, comments.comments
FROM "user" u
JOIN (SELECT user_id, count(*) as likes
    FROM likes l
    JOIN parameters par
      ON l.created_on > par.date_start AND l.created_on <= par.date_end
    GROUP BY l.user_id
) as likes ON u.id = likes.user_id
JOIN (
    SELECT user_id, count(*) as comments
    FROM comment c
    JOIN parameters par
      ON c.created_on > par.date_start AND c.created_on <= par.date_end
    GROUP BY c.user_id
) as comments ON u.id = comments.user_id

Here's a dbfiddle demo with both

PS。您的查询使用内部联接,因此只包括喜欢和评论的用户。如果用户没有评论或不喜欢任何东西,他们将被排除在外,因为连接查询不会返回任何记录。