patternsqlsqlalchemyModerate
Postgres not returning data on array_agg query as below
Viewed 0 times
array_aggpostgresquerydatareturningbelownot
Problem
The problem arise when there are no data for books in specific library. Consider a following working scenario.
Table
Table
Now when I do query like below:
The query generates output for library 1 & 2, but not for library 3. Why and how to solve this issue? (Generate an empty list on no library books)
Required Output:
I've even tried
Postgres version: 12
Table
library--------------------------------
| id | name | owner |
--------------------------------
| 1 | ABC | A |
| 2 | DEF | D |
| 3 | GHI | G |
--------------------------------Table
books--------------------------------
| id | title | library |
--------------------------------
| a | xxx | 1 |
| b | yyy | 1 |
| c | zzz | 2 |
--------------------------------Now when I do query like below:
SELECT library.name, array_agg(b.title) AS book_list FROM library,
(SELECT title FROM books WHERE books.library = :library_no) as b
WHERE library.id = :library_no GROUP BY library.idThe query generates output for library 1 & 2, but not for library 3. Why and how to solve this issue? (Generate an empty list on no library books)
Required Output:
----------------------
| name | book_list |
----------------------
| GHI | {} | # or {null}
-----------------------I've even tried
coalesce as below:SELECT library.name, coalesce(array_agg(b.title), ARRAY[]::VARCHAR[]) AS book_list FROM library,
(SELECT title FROM books WHERE books.library = :library_no) as b
WHERE library.id = :library_no GROUP BY library.idPostgres version: 12
Solution
A
But I suggest an ARRAY constructor in a
This way, you don't need to aggregate in the outer query level and don't need to
You also don't need
And it should be faster for a small selection in
Aside, you only need the variable
About
About the ARRAY constructor:
Basic about joining tables in the manual.
LEFT JOIN can solve it, like Laurenz provided.But I suggest an ARRAY constructor in a
LATERAL subquery instead:SELECT l.name, b.book_list
FROM library l
CROSS JOIN LATERAL (
SELECT ARRAY(
SELECT title
FROM books
WHERE library = l.id
)
) b(book_list)
WHERE l.id = :library_no;This way, you don't need to aggregate in the outer query level and don't need to
GROUP BY there.You also don't need
COALESCE, since the ARRAY constructor over an empty result already produces an empty array ({}).And it should be faster for a small selection in
library - obviously the query gets the result for a single given library.Aside, you only need the variable
:library_no in a single place like demonstrated.About
LATERAL joins:- What is the difference between LATERAL and a subquery in PostgreSQL?
About the ARRAY constructor:
- Why is array_agg() slower than the non-aggregate ARRAY() constructor?
Basic about joining tables in the manual.
Code Snippets
SELECT l.name, b.book_list
FROM library l
CROSS JOIN LATERAL (
SELECT ARRAY(
SELECT title
FROM books
WHERE library = l.id
)
) b(book_list)
WHERE l.id = :library_no;Context
StackExchange Database Administrators Q#283198, answer score: 10
Revisions (0)
No revisions yet.