PostgreSQL
 sql >> база данни >  >> RDS >> PostgreSQL

Използване на row_to_json() с вложени съединения

Актуализация:В PostgreSQL 9.4 това се подобрява много с въвеждането на to_json , json_build_object , json_object и json_build_array , въпреки че е многословен поради необходимостта от изрично именуване на всички полета:

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;

За по-стари версии прочетете нататък.

Не е ограничено до един ред, просто е малко болезнено. Не можете да псевдоним съставните типове редове с помощта на AS , така че трябва да използвате израз на подзаявка с псевдоним или 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;

произвежда чрез 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"
    }
  }
}

Ще искате да използвате array_to_json(array_agg(...)) когато имате връзка 1:много, между другото.

В идеалния случай горната заявка трябва да може да бъде написана като:

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;

... но ROW на PostgreSQL конструкторът не приема AS псевдоними на колони. За съжаление.

За щастие, те оптимизират същото. Сравнете плановете:

  • Вложената версия на подзаявката; срещу
  • Последният влага ROW версия на конструктор с премахнати псевдоними, така че да се изпълнява

Тъй като CTEs са оптимизационни огради, префразиране на вложената версия на подзаявка, за да се използват верижни CTE (WITH изрази) може да не се представят толкова добре и няма да доведат до същия план. В този случай сте заседнали с грозно вложени подзаявки, докато не получим някои подобрения на row_to_json или начин за замяна на имената на колоните в ROW конструктор по-директно.

Както и да е, като цяло принципът е, че където искате да създадете json обект с колони a, b, c , и бихте искали просто да напишете незаконния синтаксис:

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

вместо това можете да използвате скаларни подзаявки, връщащи въведени от ред стойности:

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

Или:

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

Освен това, имайте предвид, че можете да съставите json стойности без допълнително цитиране, напр. ако поставите изхода на json_agg в рамките на row_to_json , вътрешният json_agg резултатът няма да бъде цитиран като низ, той ще бъде включен директно като json.

напр. в произволния пример:

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
);

изходът е:

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

Имайте предвид, че json_agg продукт, [{"a":1,"b":2}, {"a":1,"b":2}] , не е екраниран отново, като text би било.

Това означава, че можете да композирате json операции за конструиране на редове, не винаги е нужно да създавате изключително сложни съставни типове PostgreSQL, след което да извикате row_to_json на изхода.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. PostgreSQL 9.2 JDBC драйвер използва клиентска часова зона?

  2. Как да добавите брой работни дни към дадена дата

  3. Използване на слотове за репликация на PostgreSQL

  4. Psql изброява всички таблици

  5. Различен db за тестване в Django?