Eu tenho esse SQL:
CREATE TABLE test(id SERIAL PRIMARY KEY, data JSONB);
INSERT INTO test(data) VALUES
('{"parent":null,"children":[2,3]}'),
('{"parent":1, "children":[4,5]}'),
('{"parent":1, "children":[]}'),
('{"parent":2, "children":[]}'),
('{"parent":2, "children":[]}');
Isso daria:
id | data
----+--------------------------------------
1 | {"parent": null, "children": [2, 3]}
2 | {"parent": 1, "children": [4, 5]}
3 | {"parent": 1, "children": []}
4 | {"parent": 2, "children": []}
5 | {"parent": 2, "children": []}
Ao fazer um para muitos normal, mostraria algo assim:
SELECT *
FROM test x1
LEFT JOIN test x2
ON x1.id = (x2.data->>'parent')::INT;
id | data | id | data
----+--------------------------------------+----+-----------------------------------
1 | {"parent": null, "children": [2, 3]} | 2 | {"parent": 1, "children": [4, 5]}
1 | {"parent": null, "children": [2, 3]} | 3 | {"parent": 1, "children": []}
2 | {"parent": 1, "children": [4, 5]} | 4 | {"parent": 2, "children": []}
2 | {"parent": 1, "children": [4, 5]} | 5 | {"parent": 2, "children": []}
5 | {"parent": 2, "children": []} | |
4 | {"parent": 2, "children": []} | |
3 | {"parent": 1, "children": []} | |
Como participar com base em filhos (usando LEFT JOIN
ou WHERE IN
)? Eu tentei:
SELECT data->>'children' FROM test;
?column?
----------
[2, 3]
[4, 5]
[]
[]
[]
SELECT json_array_elements((data->>'children')::TEXT) FROM t...
^
HINT: No function matches the given name and argument types. You might need to add explicit type casts.
SELECT json_array_elements((data->>'children')::JSONB) FROM ...
^
HINT: No function matches the given name and argument types. You might need to add explicit type casts.
SELECT json_to_record((data->>'children')::JSON) FROM test;
ERROR: function returning record called in context that cannot accept type record
HINT: Try calling the function in the FROM clause using a column definition list.
SELECT * FROM json_to_record((test.data->>'children')::JSON);
ERROR: missing FROM-clause entry for table "test"
LINE 1: SELECT * FROM json_to_record((test.data->>'children')::JSON)...
Isso seria mais eficiente:
Com
jsonb
ejsonb_array_elements_text()
na página 9.4+db<>fique aqui
Sobre
jsonb_array_elements_text()
:Use o
->
operador em vez de->>
na referência achildren
. Do jeito que você tem, você primeiro lançariajson
/jsonb
paratext
e depois voltaria parajson
.A maneira limpa de chamar uma função de retorno de conjunto é
LEFT [OUTER] JOIN LATERAL
. Isso inclui linhas sem filhos. Para excluí -los, altere para um[INNER] JOIN LATERAL
ouCROSS JOIN
- ou a sintaxe abreviada com uma vírgula:Evitando nomes de coluna duplicados no resultado.
Com
json
ejson_array_elements()
na página 9.3sqlfiddle antigo
À parte: um design de banco de dados normalizado com tipos de dados básicos seria muito mais eficiente para isso.
Não importa, eu encontrei o caminho
ou