web-dev-qa-db-fra.com

Renvoyer en tant que tableau d'objets JSON en SQL (Postgres)

J'ai le tableau suivant MyTable:

 id │ value_two │ value_three │ value_four 
────┼───────────┼─────────────┼────────────
  1 │ a         │ A           │ AA
  2 │ a         │ A2          │ AA2
  3 │ b         │ A3          │ AA3
  4 │ a         │ A4          │ AA4
  5 │ b         │ A5          │ AA5

Je souhaite interroger un tableau d'objets { value_three, value_four } Regroupés par value_two. value_two Devrait être présent seul dans le résultat. Le résultat devrait ressembler à ceci:

 value_two │                                                                                    value_four                                                                                 
───────────┼───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
 a         │ [{"value_three":"A","value_four":"AA"}, {"value_three":"A2","value_four":"AA2"}, {"value_three":"A4","value_four":"AA4"}]
 b         │ [{"value_three":"A3","value_four":"AA3"}, {"value_three":"A5","value_four":"AA5"}]

Peu importe qu'il utilise json_agg() ou array_agg().

Cependant, le mieux que je puisse faire est:

with MyCTE as ( select value_two, value_three, value_four from MyTable ) 
select value_two, json_agg(row_to_json(MyCTE)) value_four 
from MyCTE 
group by value_two;

Qui retourne:

 value_two │                                                                                    value_four                                                                                 
───────────┼───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
 a         │ [{"value_two":"a","value_three":"A","value_four":"AA"}, {"value_two":"a","value_three":"A2","value_four":"AA2"}, {"value_two":"a","value_three":"A4","value_four":"AA4"}]
 b         │ [{"value_two":"b","value_three":"A3","value_four":"AA3"}, {"value_two":"b","value_three":"A5","value_four":"AA5"}]

Avec une clé supplémentaire value_two Dans les objets, dont je voudrais me débarrasser. Quelle requête SQL (Postgres) dois-je utiliser?

20
ehmicky

json_build_object() dans Postgres 9.4 ou plus récent

SELECT value_two, json_agg(json_build_object('value_three', value_three
                                           , 'value_four' , value_four)) AS value_four
FROM   mytable 
GROUP  BY value_two;

Le manuel:

Construit un objet JSON à partir d'une liste d'arguments variadiques. Par convention, la liste d'arguments consiste en une alternance de clés et de valeurs.

Pour toutes les versions (y compris Postgres 9.3)

row_to_json() avec une expression ROW ferait l'astuce:

SELECT value_two
     , json_agg(row_to_json((value_three, value_four))) AS value_four
FROM   mytable
GROUP  BY value_two;

Mais vous perdez les noms de colonnes d'origine. Un transtypage en un type de ligne enregistré évite cela. (Le type de ligne d'une table temporaire sert également aux requêtes ad hoc.)

CREATE TYPE foo AS (value_three text, value_four text);  -- once in the same session
SELECT value_two
     , json_agg(row_to_json((value_three, value_four)::foo)) AS value_four
FROM   mytable
GROUP  BY value_two;

Ou utilisez une sous-sélection au lieu de l'expression ROW. Plus verbeux, mais sans fonte de type:

SELECT value_two
     , json_agg(row_to_json((SELECT t FROM (SELECT value_three, value_four) t))) AS value_four
FROM   mytable
GROUP  BY value_two;

Plus d'explications dans la réponse connexe de Craig:

db <> violon ici
Ancien violon SQL.

50
Erwin Brandstetter