Как сгруппировать несколько столбцов в один массив или аналог? - PullRequest
0 голосов
/ 11 февраля 2019

Я бы хотел, чтобы мой запрос возвращал результат, структурированный следующим образом, где tags - это массив массивов или аналогичный:

id | name | tags
1    a      [[1, "name1", "color1"], [2, "name2", color2"]]
2    b      [[1, "name1", "color1"), (3, "name3", color3"]]

Я ожидал, что этот запрос будет работать, но он выдает ошибку:

SELECT  i.id, i.name, array_agg(t.tag_ids, t.tag_names, t.tag_colors) as tags 
FROM    ITEMS
LEFT OUTER JOIN (
  SELECT      trm.target_record_id
            , array_agg(tag_id) as tag_ids
            , array_agg(t.tag_name) as tag_names
            , array_agg(t.tag_color) as tag_colors
  FROM        tags_record_maps trm
  INNER JOIN  tags t on t.id = trm.tag_id
  GROUP BY    trm.target_record_id
) t on t.target_record_id = i.id;

Ошибка:

PG::UndefinedFunction: ERROR:  function array_agg(integer[], character varying[], character varying[]) does not exist
LINE 1: ..., action_c2, action_c3, action_name, action_desc, array_agg(...
HINT:  No function matches the given name and argument types. You might need to add explicit type casts.

Этот запрос работает и дает аналогичные результаты (но не совсем то, что я хочу):

SELECT  i.id, i.name, t.tag_ids, t.tag_names, t.tag_colors as tags  as tags 
FROM    ITEMS
LEFT OUTER JOIN (
  SELECT      trm.target_record_id, array_agg(tag_id) as tag_ids, array_agg(t.tag_name) as tag_names, array_agg(t.tag_color) as tag_colors
  FROM        tags_record_maps trm
  INNER JOIN  tags t on t.id = trm.tag_id
  GROUP BY    trm.target_record_id
) t on t.target_record_id = i.id;

Результат:

id | name | tag_ids | tag_names         | tag_colors          
1    a      [1, 2]    ["name1, "name2"]   ["color1", "color2"]
1    a      [1, 3]    ["name1, "name3"]   ["color1", "color3"]

Редактировать:

Этот запрос почти производит то, что я ищу, кроме того, что называет json-ключи f1, f2, f3.Было бы идеально, если бы я мог назвать их id, name, color:

  SELECT        trm.target_record_id, json_agg( (t.id, t.tag_name, t.tag_color) )
  FROM          tags_record_maps trm
  INNER JOIN    tags t on t.site_id = trm.site_id and t.id = trm.tag_id
  GROUP BY      trm.target_record_id
  having count(*) > 1;

Результат:

[{"f1":1,"f2":"name1","f3":"color1"},{"f1":2,"f2":"name2","f3":"color2"}]

Ответы [ 3 ]

0 голосов
/ 11 февраля 2019

array_agg() помещает один аргумент в массив.Вы можете попытаться объединить значения вместе:

array_agg(t.tag_ids || ':' || t.tag_names || ':' || t.tag_colors)

Или, возможно, использовать конструктор строки:

array_agg( (t.tag_ids, t.tag_names, t.tag_colors) )
0 голосов
/ 12 февраля 2019

(t.id, t.tag_name, t.tag_color) - короткий синтаксис для ROW(t.id, t.tag_name, t.tag_color) - и конструктор ROW не сохраняет имена вложенных атрибутов. Руководство:

По умолчанию значение, создаваемое выражением ROW, имеет анонимный тип записи .При необходимости он может быть приведен к названному составному типу - либо к типу строки таблицы, либо к составному типу, созданному с помощью CREATE TYPE AS.

.Чтобы также получить правильные имена ключей в результате, приведите к зарегистрированному составному типу, как рекомендовано в цитате, используйте вложенный вложенный выбор или просто используйте json_build_object() в Postgres 9.4 или новее (эффективно избегая конструктора ROW априори):

SELECT trm.target_record_id
     , <b>json_agg(json_build_object('id', t.id
                                , 'tag_name', t.tag_name
                                , 'tag_color', t.tag_color)) AS tags</b>
FROM   tags_record_maps trm
JOIN   tags             t USING (site_id)
WHERE  t.id = trm.tag_id
GROUP  BY trm.target_record_id
HAVING count(*) > 1;

Я использую оригинальные имена столбцов, но вы можете свободно выбирать имена ключей.В вашем случае:

       json_agg(json_build_object('id', t.id
                                , 'name', t.tag_name
                                , 'color', t.tag_color)) AS tags

Подробное объяснение:

0 голосов
/ 11 февраля 2019

Почему бы не попробовать Json_Agg()?

SELECT 
     json_agg(tag_ids, tag_names, tag_colors)
FROM items

И т.д ...

...