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

PostgreSQL връща набор от резултати като JSON масив?

TL;DR

SELECT json_agg(t) FROM t

за JSON масив от обекти и

SELECT
    json_build_object(
        'a', json_agg(t.a),
        'b', json_agg(t.b)
    )
FROM t

за JSON обект от масиви.

Списък с обекти

Този раздел описва как да генерирате JSON масив от обекти, като всеки ред се преобразува в един обект. Резултатът изглежда така:

[{"a":1,"b":"value1"},{"a":2,"b":"value2"},{"a":3,"b":"value3"}]

9.3 и по-нови версии

json_agg функция произвежда този резултат извън кутията. Той автоматично разбира как да преобразува входа си в JSON и го агрегира в масив.

SELECT json_agg(t) FROM t

Няма jsonb (въведена в 9.4) версия на json_agg . Можете или да агрегирате редовете в масив и след това да ги конвертирате:

SELECT to_jsonb(array_agg(t)) FROM t

или комбинирайте json_agg с отливка:

SELECT json_agg(t)::jsonb FROM t

Моето тестване предполага, че агрегирането им в масив първо е малко по-бързо. Подозирам, че това е така, защото предаването трябва да анализира целия JSON резултат.

9.2

9.2 няма json_agg или to_json функции, така че трябва да използвате по-стария array_to_json :

SELECT array_to_json(array_agg(t)) FROM t

По желание можете да включите row_to_json обадете се в заявката:

SELECT array_to_json(array_agg(row_to_json(t))) FROM t

Това преобразува всеки ред в JSON обект, агрегира JSON обектите като масив и след това преобразува масива в JSON масив.

Не успях да открия някаква значителна разлика в производителността между двете.

Обект на списъци

Този раздел описва как да генерирате JSON обект, като всеки ключ е колона в таблицата и всяка стойност е масив от стойностите на колоната. Това е резултатът, който изглежда така:

{"a":[1,2,3], "b":["value1","value2","value3"]}

9.5 и нагоре

Можем да използваме json_build_object функция:

SELECT
    json_build_object(
        'a', json_agg(t.a),
        'b', json_agg(t.b)
    )
FROM t

Можете също така да агрегирате колоните, създавайки един ред и след това да го конвертирате в обект:

SELECT to_json(r)
FROM (
    SELECT
        json_agg(t.a) AS a,
        json_agg(t.b) AS b
    FROM t
) r

Имайте предвид, че псевдонимът на масивите е абсолютно необходим, за да се гарантира, че обектът има желаните имена.

Кое е по-ясно е въпрос на мнение. Ако използвате json_build_object функция, силно препоръчвам да поставите една двойка ключ/стойност на ред, за да подобрите четливостта.

Можете също да използвате array_agg на мястото на json_agg , но моето тестване показва, че json_agg е малко по-бързо.

Няма jsonb версия на json_build_object функция. Можете да агрегирате в един ред и да конвертирате:

SELECT to_jsonb(r)
FROM (
    SELECT
        array_agg(t.a) AS a,
        array_agg(t.b) AS b
    FROM t
) r

За разлика от другите заявки за този вид резултати, array_agg изглежда е малко по-бърз при използване на to_jsonb . Подозирам, че това се дължи на главен анализ и валидиране на JSON резултата от json_agg .

Или можете да използвате изрично прехвърляне:

SELECT
    json_build_object(
        'a', json_agg(t.a),
        'b', json_agg(t.b)
    )::jsonb
FROM t

to_jsonb версията ви позволява да избягвате прехвърлянето и е по-бърза, според моето тестване; отново подозирам, че това се дължи на излишни разходи при анализиране и валидиране на резултата.

9.4 и 9.3

json_build_object функцията беше нова за 9.5, така че трябва да агрегирате и конвертирате в обект в предишни версии:

SELECT to_json(r)
FROM (
    SELECT
        json_agg(t.a) AS a,
        json_agg(t.b) AS b
    FROM t
) r

или

SELECT to_jsonb(r)
FROM (
    SELECT
        array_agg(t.a) AS a,
        array_agg(t.b) AS b
    FROM t
) r

в зависимост от това дали искате json или jsonb .

(9.3 няма jsonb .)

9.2

В 9.2 дори не to_json съществува. Трябва да използвате row_to_json :

SELECT row_to_json(r)
FROM (
    SELECT
        array_agg(t.a) AS a,
        array_agg(t.b) AS b
    FROM t
) r

Документация

Намерете документацията за функциите JSON във функциите на JSON.

json_agg е на страницата с обобщени функции.

Дизайн

Ако производителността е важна, уверете се, че сравнявате заявките си с вашата собствена схема и данни, вместо да се доверявате на моето тестване.

Дали е добър дизайн или не зависи от конкретното ви приложение. По отношение на поддръжката не виждам особен проблем. Това опростява кода на приложението ви и означава, че има по-малко за поддържане в тази част от приложението. Ако PG може да ви даде точно желания резултат от кутията, единствената причина, която се сещам да не го използвам, е съображенията за производителност. Не изобретявайте колелото и всичко останало.

Нули

Агрегатните функции обикновено връщат NULL когато работят над нула редове. Ако това е възможно, може да искате да използвате COALESCE за да ги избягвам. Няколко примера:

SELECT COALESCE(json_agg(t), '[]'::json) FROM t

Или

SELECT to_jsonb(COALESCE(array_agg(t), ARRAY[]::t[])) FROM t

Кредит на Ханес Ландехолм, че посочи това



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Как Asinh() работи в PostgreSQL

  2. PostgreSQL:сериен срещу самоличност

  3. кръстосана таблица с 2 (или повече) имена на редове

  4. Как работи Width_Bucket() в PostgreSQL

  5. Файл на сокет /var/pgsql_socket/.s.PGSQL.5432 липсва в Mountain Lion (OS X сървър)