sql >> Database teknologi >  >> RDS >> PostgreSQL

Brug af row_to_json() med indlejrede joinforbindelser

Opdatering:I PostgreSQL 9.4 forbedres dette meget med introduktionen af ​​to_json , json_build_object , json_object og json_build_array , selvom det er ordrigt på grund af behovet for at navngive alle felterne eksplicit:

vælg json_build_object( 'id', u.id, 'name', u.name, 'email', u.email, 'user_role_id', u.user_role_id, 'user_role', json_build_object( 'id' , ur.id, 'name', ur.name, 'description', ur.description, 'duty_id', ur.duty_id, 'duty', json_build_object( 'id', d.id, 'name', d.name ) ) )fra brugere uinner join user_roles ur on ur.id =u.user_role_idnner join role_duties d on d.id =ur.duty_id; 

For ældre versioner, læs videre.

Det er ikke begrænset til en enkelt række, det er bare en smule smertefuldt. Du kan ikke kalde sammensatte rækketyper ved at bruge AS , så du skal bruge et aliaseret underforespørgselsudtryk eller CTE for at opnå effekten:

vælg row_to_json(row)from ( vælg u.*, urd AS user_role fra brugere u indre joinforbindelse ( vælg ur.*, d fra user_rolles ur indre join role_duties d on d.id =ur.duty_id ) urd (id,name,description,duty_id,duty) på urd.id =u.user_role_id) række; 

producerer, via http://jsonprettyprint.com/:

{ "id":1, "name":"Dan", "email":"[email protected]", "user_role_id":1, "user_role":{ "id":1, "name":"admin", "description":"Administrative opgaver i systemet", "duty_id":1, "duty":{ "id":1, "name":"Scriptudførelse" } }} 

Du vil gerne bruge array_to_json(array_agg(...)) når man har et 1:mange forhold, btw.

Ovenstående forespørgsel bør ideelt set kunne skrives som:

vælg row_to_json( ROW(u.*, ROW(ur.*, d AS duty) AS user_role))from users uinner join user_roles ur on ur.id =u.user_role_dinner join role_duties d on d.id =ur.duty_id; 

... men PostgreSQL's ROW konstruktør accepterer ikke AS kolonnealiasser. Desværre.

Heldigvis optimerer de det samme. Sammenlign planerne:

  • Den indlejrede underforespørgselversion; vs.
  • Sidstnævnte indlejrede ROW konstruktørversion med aliasserne fjernet, så den udføres

Fordi CTE'er er optimeringshegn, omformulerer den indlejrede underforespørgselsversion til at bruge kædede CTE'er (WITH udtryk) fungerer muligvis ikke så godt og vil ikke resultere i den samme plan. I dette tilfælde sidder du lidt fast med grimme indlejrede underforespørgsler, indtil vi får nogle forbedringer til row_to_json eller en måde at tilsidesætte kolonnenavnene i en ROW konstruktør mere direkte.

Generelt er princippet i hvert fald, at hvor du vil oprette et json-objekt med kolonner a, b, c , og du ville ønske, at du bare kunne skrive den ulovlige syntaks:

ROW(a, b, c) AS ydernavn(navn1, navn2, navn3) 

du kan i stedet bruge skalære underforespørgsler, der returnerer rækketypeværdier:

(SELECT x FROM (VÆLG a AS navn1, b AS navn2, c AS navn3) x) AS ydernavn 

Eller:

(SELECT x FROM (SELECT a, b, c) AS x(name1, name2, name3)) AS ydernavn 

Derudover skal du huske på, at du kan komponere json værdier uden yderligere citering, f.eks. hvis du sætter output fra en json_agg inden for en row_to_json , den indre json_agg Resultatet bliver ikke citeret som en streng, det vil blive indarbejdet direkte som json.

for eksempel. i det vilkårlige eksempel:

SELECT row_to_json( (SELECT x FROM (SELECT 1 AS k1, 2 AS k2, (SELECT json_agg( (SELECT x FROM (SELECT 1 AS a, 2 AS b) x) ) FROM gener_series(1,2) ) ) AS k3 ) x), sand); 

outputtet er:

{"k1":1, "k2":2, "k3":[{"a":1,"b":2}, {"a":1,"b":2 }]}

Bemærk, at json_agg produkt, [{"a":1,"b":2}, {"a":1,"b":2}] , er ikke blevet escaped igen, som tekst ville være.

Det betyder, at du kan skrive json-operationer for at konstruere rækker, behøver du ikke altid at skabe enormt komplekse PostgreSQL-sammensatte typer og derefter kalde row_to_json på udgangen.



  1. Opdel en kolonne i flere rækker

  2. Forståelse af 'datetimeoffset' Storage Size i SQL Server

  3. MySQL vs. MongoDB

  4. Brug af variabel i en LIMIT-klausul i MySQL