O problema surge quando não há dados para livros em uma biblioteca específica. Considere um cenário de trabalho a seguir.
Mesalibrary
--------------------------------
| id | name | owner |
--------------------------------
| 1 | ABC | A |
| 2 | DEF | D |
| 3 | GHI | G |
--------------------------------
Mesabooks
--------------------------------
| id | title | library |
--------------------------------
| a | xxx | 1 |
| b | yyy | 1 |
| c | zzz | 2 |
--------------------------------
Agora, quando eu faço consulta como abaixo:
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.id
A consulta gera saída para a biblioteca 1 e 2, mas não para a biblioteca 3. Por que e como resolver esse problema? (Gerar uma lista vazia em nenhum livro da biblioteca)
Saída necessária:
----------------------
| name | book_list |
----------------------
| GHI | {} | # or {null}
-----------------------
Eu até tentei coalesce
como abaixo:
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.id
Versão do Postgres: 12
A
LEFT JOIN
pode resolvê-lo, como Laurenz forneceu.Mas sugiro um construtor ARRAY em uma
LATERAL
subconsulta:Dessa forma, você não precisa agregar no nível de consulta externa e não precisa fazer
GROUP BY
isso.Você também não precisa
COALESCE
, pois o construtor ARRAY sobre um resultado vazio já produz um array vazio ({}
).E deve ser mais rápido para uma pequena seleção
library
- obviamente, a consulta obtém o resultado para uma única biblioteca.Além disso, você só precisa da variável
:library_no
em um único local, como demonstrado.Sobre
LATERAL
as junções:Sobre o construtor ARRAY:
Básico sobre como juntar tabelas no manual .
Você precisa de uma junção à esquerda:
Então você também terá bibliotecas sem livros.