Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

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

Provided you have three tables (user, comment, like)

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;

Is there any way to simplify a query like this? Could the created_on filter dates be declared as variables?

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

>Solution :

PL/pgSQL supports variables inside functions, so you could make this a function if you wanted and then query the function results. Say something like:

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;

You’d then query it:

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

Of course that’s probably not what you’re after. If you want variables when "just querying", it’ll depend on the client you’re using. If you’re using psql, it does support variables. Other clients may or may not support them, depends.

What you can also do is to rework the query a little bit, like so, with a parameters CTE at the beginning and then use it to join the selected params:

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. Your queries use inner join so will only include users who both liked and commented. If a user didn’t comment, or didn’t like anything, they will be excluded because no records will be returned from the joined query.

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading