Mam kolumnę, data
która zawiera json
mniej więcej taki dokument:
{
"name": "foo",
"tags": ["foo", "bar"]
}
Chciałbym przekształcić zagnieżdżoną tags
tablicę w konkatenowany ciąg ( foo, bar
). Byłoby to łatwo możliwe z array_to_string()
funkcją w teorii. Ta funkcja nie działa jednak na json
tablice. Zastanawiam się więc, jak zmienić tę json
tablicę w Postgres array
?
postgresql
postgresql-9.3
array
json
Christoph
źródło
źródło
json_extract_path_text(your_column, 'tags')
tego szukasz?Odpowiedzi:
Postgres 9.4 lub nowszy
Oczywiście zainspirowany tym postem Postgres 9.4 dodał brakujące funkcje:
Podziękowania dla Laurence'a Rowe za łatkę i Andrew Dunstana za zatwierdzenie!
json_array_elements_text(json)
jsonb_array_elements_text(jsonb)
Aby odczepić tablicę JSON. Następnie użyj
array_agg()
lub konstruktora ARRAY, aby zbudować z niego tablicę Postgres . Lubstring_agg()
zbudowaćtext
ciąg .Agreguj niezanieczyszczone elementy na wiersz w
LATERAL
podkwerendie lub skorelowanej. Następnie pierwotny porządek jest zachowany i nie musimyORDER BY
,GROUP BY
a nawet unikalny klucz w zapytaniu zewnętrznym. Widzieć:Zamień „json” na „jsonb” dla
jsonb
wszystkich następujących kodów SQL.Krótka składnia:
Związane z:
Konstruktor ARRAY w skorelowanym podzapytaniu:
Związane z:
Subtelna różnica :
null
elementy są zachowywane w rzeczywistych tablicach . Nie jest to możliwe w powyższych zapytaniach generującychtext
ciąg, który nie może zawieraćnull
wartości. Prawdziwy obraz jest tablicą.Opakowanie funkcji
W celu wielokrotnego użycia, aby uczynić to jeszcze prostszym, enkapsuluj logikę w funkcji:
Zrób z tego funkcję SQL , aby można ją było wstawiać w większych zapytaniach.
Zrób to
IMMUTABLE
(bo tak jest), aby uniknąć powtarzania oceny w większych zapytaniach i zezwól na to w wyrażeniach indeksowych.Połączenie:
db <> skrzypce tutaj
Postgres 9.3 lub starszy
Użyj funkcji
json_array_elements()
. Ale otrzymujemy z niego ciągi cudzysłowów .Alternatywne zapytanie z agregacją w zapytaniu zewnętrznym.
CROSS JOIN
usuwa wiersze z brakującymi lub pustymi tablicami. Może być również przydatny do przetwarzania elementów. Potrzebujemy unikalnego klucza do agregacji:Konstruktor ARRAY, wciąż z ciągami cytowanymi:
Zauważ, że
null
jest konwertowany na wartość tekstową „null”, inaczej niż powyżej. Niepoprawne, ściśle mówiąc i potencjalnie dwuznaczne.Biedny człowiek nie cytuje
trim()
:Pobierz pojedynczy wiersz z tbl:
Ciągi tworzą skorelowane podzapytanie:
Konstruktor ARRAY:
Oryginalne (nieaktualne) skrzypce SQL .
db <> skrzypce tutaj.
Związane z:
Uwagi (nieaktualne od str. 9.4)
Potrzebowalibyśmy
json_array_elements_text(json)
bliźniaka,json_array_elements(json)
aby zwrócić odpowiednietext
wartości z tablicy JSON. Ale wydaje się, że brakuje tego w arsenale funkcji JSON . Lub inna funkcja do wyodrębnieniatext
wartości zJSON
wartości skalarnej . Wydaje mi się, że też tego brakuje.Więc improwizowałem
trim()
, ale to się nie powiedzie w nietrywialnych przypadkach ...źródło
to_jsonb()
Użyłbyś do konwersji tablica-> jsonb.SELECT ARRAY(SELECT json_array_elements_text(_js))
naprawdę gwarantuje zachowanie kolejności tablic? Czy optymalizator nie może teoretycznie zmieniać kolejności wierszy wychodzących z tekstu json_array_elements_text?PG 9.4+
Akceptowana odpowiedź jest zdecydowanie tym, czego potrzebujesz, ale dla uproszczenia oto pomocnik, którego używam do tego:
Następnie po prostu wykonaj:
źródło
To pytanie zostało zadane na listach mailingowych PostgreSQL i wymyśliłem ten hackerski sposób konwersji tekstu JSON na tekst PostgreSQL za pomocą operatora ekstrakcji pola JSON:
Zasadniczo konwertuje wartość na tablicę jednoelementową, a następnie prosi o pierwszy element.
Innym podejściem byłoby użycie tego operatora do wyodrębnienia wszystkich pól jeden po drugim. Ale w przypadku dużych tablic jest to prawdopodobnie wolniejsze, ponieważ musi przeanalizować cały ciąg JSON dla każdego elementu tablicy, co prowadzi do złożoności O (n ^ 2).
źródło
Przetestowałem kilka opcji. Oto moje ulubione zapytanie. Załóżmy, że mamy tabelę zawierającą pole id i json. Pole json zawiera tablicę, którą chcemy przekształcić w tablicę pg.
Działa gdziekolwiek i szybciej niż inne, ale wygląda chudo)
Najpierw tablica json jest rzutowana jako tekst, a następnie zmieniamy nawiasy kwadratowe na nawiasy. Na koniec tekst jest rzutowany jako tablica wymaganego typu.
a jeśli wolisz tablice tekstowe []
źródło
SELECT TRANSLATE('{"name": "foo", "tags": ["foo", "bar"]}'::jsonb::text, '[]','{}')::INT[]; ERROR: malformed array literal: "{"name": "foo", "tags": {"foo", "bar"}}"
Myślę, że musisz dodać wyjaśnienie, jak to ma działać.SELECT translate('["foo", "bar"]'::jsonb::text, '[]','{}')::INT[]; ERROR: invalid input syntax for integer: "foo"
Nie jest tak odporny na bomby ...Tych kilku funkcji, zaczerpniętych z odpowiedzi na to pytanie , używam i działają świetnie
W każdym z nich, łącząc się z pustą tablicą, zajmują się sprawą, która zmusiła mnie do drżenia mózgu przez chwilę, w tym przypadku, jeśli spróbujesz rzucić pustą tablicę z
json
/jsonb
bez niej, nic nie otrzymasz, zamiast pusta tablica ({}
), jak można się spodziewać. Jestem pewien, że istnieje dla nich pewna optymalizacja, ale zostały one uproszczone w objaśnieniu tej koncepcji.źródło