PostgreSQL
 sql >> Baza danych >  >> RDS >> PostgreSQL

Używanie row_to_json() z połączeniami zagnieżdżonymi

Aktualizacja:W PostgreSQL 9.4 znacznie się to poprawia dzięki wprowadzeniu to_json , json_build_object , json_object i json_build_array , choć jest to gadatliwe ze względu na konieczność wyraźnego nazwania wszystkich pól:

select
        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
                        )
                )
    )
from users u
inner join user_roles ur on ur.id = u.user_role_id
inner join role_duties d on d.id = ur.duty_id;

W przypadku starszych wersji czytaj dalej.

Nie ogranicza się do jednego rzędu, to po prostu trochę bolesne. Nie można aliasować złożonych typów wierszy za pomocą AS , więc aby uzyskać ten efekt, musisz użyć aliasowanego wyrażenia podzapytania lub CTE:

select row_to_json(row)
from (
    select u.*, urd AS user_role
    from users u
    inner join (
        select ur.*, d
        from user_roles ur
        inner join role_duties d on d.id = ur.duty_id
    ) urd(id,name,description,duty_id,duty) on urd.id = u.user_role_id
) row;

produkuje, za pośrednictwem http://jsonprettyprint.com/:

{
  "id": 1,
  "name": "Dan",
  "email": "[email protected]",
  "user_role_id": 1,
  "user_role": {
    "id": 1,
    "name": "admin",
    "description": "Administrative duties in the system",
    "duty_id": 1,
    "duty": {
      "id": 1,
      "name": "Script Execution"
    }
  }
}

Będziesz chciał użyć array_to_json(array_agg(...)) kiedy masz związek 1:wielu, przy okazji.

Najlepiej byłoby, gdyby powyższe zapytanie można było zapisać jako:

select row_to_json(
    ROW(u.*, ROW(ur.*, d AS duty) AS user_role)
)
from users u
inner join user_roles ur on ur.id = u.user_role_id
inner join role_duties d on d.id = ur.duty_id;

... ale ROW PostgreSQLa Konstruktor nie akceptuje AS aliasy kolumn. Niestety.

Na szczęście optymalizują to samo. Porównaj plany:

  • Wersja zagnieżdżonego podzapytania; vs
  • Ostatni zagnieżdżony ROW wersja konstruktora z usuniętymi aliasami, więc wykonuje się

Ponieważ CTE są ograniczeniami optymalizacji, przeformułowanie zagnieżdżonej wersji podzapytania w celu użycia połączonych CTE (WITH wyrażenia) mogą nie działać tak dobrze i nie będą skutkować tym samym planem. W tym przypadku utkniesz z brzydkimi zagnieżdżonymi podzapytaniami, dopóki nie uzyskamy pewnych ulepszeń w row_to_json lub sposób na nadpisanie nazw kolumn w ROW Konstruktor bardziej bezpośrednio.

W każdym razie generalnie zasada jest taka, że ​​tam, gdzie chcesz utworzyć obiekt json z kolumnami a, b, c , i chcesz po prostu napisać nieprawidłową składnię:

ROW(a, b, c) AS outername(name1, name2, name3)

możesz zamiast tego użyć podzapytań skalarnych zwracających wartości wpisane w wiersze:

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

Lub:

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

Dodatkowo pamiętaj, że możesz komponować json wartości bez dodatkowego cytowania, np. jeśli umieścisz wyjście json_agg w row_to_json , wewnętrzny json_agg wynik nie będzie cytowany jako ciąg, zostanie dołączony bezpośrednio jako json.

np. w dowolnym przykładzie:

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 generate_series(1,2) ) AS k3
        ) x),
        true
);

wyjście to:

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

Zauważ, że json_agg produkt, [{"a":1,"b":2}, {"a":1,"b":2}] , nie został ponownie zmieniony, ponieważ text byłoby.

Oznacza to, że możesz komponować operacje json do konstruowania wierszy, nie zawsze musisz tworzyć bardzo złożone typy złożone PostgreSQL, a następnie wywoływać row_to_json na wyjściu.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Zwiększanie wydajności PostgreSQL dzięki HAProxy

  2. Jak skopiować z pliku CSV do tabeli PostgreSQL z nagłówkami w pliku CSV?

  3. Uzyskaj domyślną wartość szeregową po INSERT wewnątrz PL/pgSQL

  4. Wartość referencyjna kolumny serii w innej kolumnie podczas tej samej INSERT

  5. Funkcja LEAST() w PostgreSQL