json
w Postgresie 9.3
Jest to trudne na stronie 9.3, ponieważ brakuje użytecznych funkcji.
Metoda 1
Rozpakuj w LEFT JOIN LATERAL
(czysty i zgodny ze standardami), skróć podwójne cudzysłowy z json
po przesłaniu do text
. Zobacz linki poniżej.
SELECT DISTINCT ON (1)
t.id, t.name, d.last
FROM tbl t
LEFT JOIN LATERAL (
SELECT ('[' || d::text || ']')::json->>0 AS last
FROM json_array_elements(t.data) d
) d ON d.last <> t.name
ORDER BY 1, row_number() OVER () DESC;
Chociaż to działa i nigdy nie widziałem, żeby to zawiodło, kolejność niezagnieżdżonych elementów zależy od nieudokumentowanego zachowania. Zobacz linki poniżej!
Poprawiono konwersję z json
do text
z wyrażeniem dostarczone przez @pozs w komentarzu
. Nadal hackowy, ale powinien być bezpieczny.
Metoda 2
SELECT DISTINCT ON (1)
id, name, NULLIF(last, name) AS last
FROM (
SELECT t.id, t.name
,('[' || json_array_elements(t.data)::text || ']')::json->>0 AS last
, row_number() OVER () AS rn
FROM tbl t
) sub
ORDER BY 1, (last = name), rn DESC;
- Rozpakuj w
SELECT
lista (niestandardowa). - Dołącz numer wiersza (
rn
) równolegle (bardziej niezawodne). - Konwertuj na
text
jak powyżej. - Wyrażenie
(last = name)
wORDER BY
klauzula sortuje pasujące nazwy na końcu (ale przed NULL). Tak więc pasująca nazwa jest wybierana tylko wtedy, gdy żadna inna nazwa nie jest dostępna. Ostatni link poniżej.WSELECT
lista,NULLIF
zastępuje pasującą nazwęNULL
, uzyskując taki sam wynik jak powyżej.
json
lub jsonb
w Postgresie 9.4
strona 9.4 dostarcza wszystkie niezbędne ulepszenia:
SELECT DISTINCT ON (1)
t.id, t.name, d.last
FROM tbl t
LEFT JOIN LATERAL json_array_elements_text(data) WITH ORDINALITY d(last, rn)
ON d.last <> t.name
ORDER BY d.rn DESC;
Użyj jsonb_array_elements_text()
dla jsonb
. Wszystko inne to samo.
funkcje json/jsonb w instrukcji
Powiązane odpowiedzi z dodatkowym wyjaśnieniem:
- Jak zamienić tablicę json w tablicę postgres?
- PostgreSQL unnest() z numerem elementu
- Indeks do znajdowania elementu w tablicy JSON
- Priorytet oparty na czasie w Zapytanie o aktywny rekord
- Wybierz najpierw wiersz w każdej grupie GROUP BY?