当聚合来自多个内部查询的数据时,如何避免冗长和简化?
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。您的查询使用内部联接,因此只包括喜欢和评论的用户。如果用户没有评论或不喜欢任何东西,他们将被排除在外,因为连接查询不会返回任何记录。
前提是你有三张表(用户、评论、点赞)
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。您的查询使用内部联接,因此只包括喜欢和评论的用户。如果用户没有评论或不喜欢任何东西,他们将被排除在外,因为连接查询不会返回任何记录。