Search code examples
sqlpostgresqljoinarray-agg

How to get an empty array in array_agg if condition is not met?


I have 2 tables:

collections_books (collection_id, book_id)
users_collections (user_id, collection_id, access)

I'm using PostgreSQL.

The following query gives me a list of book_ids grouped by collection_ids. The problem is, since I'm using where condition, the results are limited to only the collections allowed for user_id = 3.

But, I want all the collection_ids and the corresponding book_ids

  1. As an array, if the user_id has access = allow
  2. As an empty array, if the user_id is not present in the users_collections or user_id != allow
SELECT c.collection_id, ARRAY_AGG(c.book_id)
FROM collections_books AS c
LEFT JOIN users_collections AS u
ON c.collection_id = u.collection_id
WHERE 
  u.access = 'allow' AND
  u.user_id = 3
GROUP BY c.collection_id;

Solution

  • Please check out below answer and let me know whether it returns your desired output or not:

    Schema and insert statements:

         create table users_collections (user_id int, collection_id int, access varchar(20));
         insert into users_collections values(3, 1, 'allow');
         insert into users_collections values(3, 2, 'allow');
         insert into users_collections values(4, 3, 'allow');
         insert into users_collections values(3, 5, 'not allow');
    
     
         create table collections_books (collection_id int, book_id int);
         insert into collections_books values(2,24);
         insert into collections_books values(3,35);
         insert into collections_books values(3,25);
         insert into collections_books values(1,36);
         insert into collections_books values(1,22);
         insert into collections_books values(1,24);
         insert into collections_books values(2,34);
         insert into collections_books values(5,344);
         insert into collections_books values(6,474);
    

    Query:

         SELECT c.collection_id, (CASE WHEN max(u.access) = 'allow' AND max(u.user_id) = 3
         THEN ARRAY_AGG(c.book_id)
         ELSE '{null}'::int[] END)
         FROM collections_books AS c
         LEFT JOIN users_collections AS u
         ON c.collection_id = u.collection_id
         GROUP BY c.collection_id;
     
    

    Output:

     |collection_id | case      |
     |------------: | :---------|
     |            3 | {35,25}   |
     |            5 | {NULL}    |
     |            6 | {NULL}    |
     |            2 | {24,34}   |
     |            1 | {36,24,22}|
    

    db<fiddle here