json
i Postgres 9.3
Detta är svårt i sidan 9.3, eftersom användbar funktionalitet saknas.
Metod 1
Unnest i en LEFT JOIN LATERAL
(ren och standardanpassad), trimma dubbla citattecken från json
efter casting till text
. Se länkar nedan.
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;
Även om detta fungerar, och jag har aldrig sett det misslyckas, beror ordningen på okapslade element på odokumenterat beteende. Se länkar nedan!
Förbättrade konverteringen från json
till text
med uttrycket tillhandahålls av @pozs i kommentaren
. Fortfarande hackigt, men borde vara säkert.
Metod 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;
- Unnest i
SELECT
lista (icke-standard). - Bifoga radnummer (
rn
) parallellt (mer tillförlitlig). - Konvertera till
text
som ovan. - Uttrycket
(last = name)
iORDER BY
sats sorterar matchande namn efter (men före NULL). Så ett matchande namn väljs bara om inget annat namn är tillgängligt. Sista länken nedan. ISELECT
lista,NULLIF
ersätter ett matchande namn medNULL
, vilket kommer fram till samma resultat som ovan.
json
eller jsonb
i Postgres 9.4
pg 9.4 levererar alla nödvändiga förbättringar:
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;
Använd jsonb_array_elements_text()
för jsonb
. Allt annat lika.
json / jsonb-funktioner i manualen
Relaterade svar med mer förklaring:
- Hur förvandlar man json-array till postgres-array?
- PostgreSQL unnest() med elementnummer
- Index för att hitta ett element i en JSON-array
- Tidsbaserad prioritet i Aktiv postfråga
- Välj först rad i varje GROUP BY-grupp?