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
SELECTlista (icke-standard). - Bifoga radnummer (
rn) parallellt (mer tillförlitlig). - Konvertera till
textsom ovan. - Uttrycket
(last = name)iORDER BYsats 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. ISELECTlista,NULLIFersä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?