Эквивалент Postgresql GROUP_CONCAT?

У меня есть таблица, и я хотел бы вытащить одну строку для каждого идентификатора с объединенными значениями полей.

В моей таблице, например, есть такое:

TM67 | 4  | 32556
TM67 | 9  | 98200
TM67 | 72 | 22300
TM99 | 2  | 23009
TM99 | 3  | 11200

И я хочу вывести:

TM67 | 4,9,72 | 32556,98200,22300
TM99 | 2,3    | 23009,11200

В MySQL мне удалось использовать агрегатную функцию GROUP_CONCAT, но, похоже, здесь она не работает ... Есть ли эквивалент для PostgreSQL или другой способ сделать это?


person TwixxyKit    schedule 01.04.2010    source источник
comment
Не ответ, но посмотрите postgresonline.com/journal/index.php?/archives/.   -  person Kuberchaun    schedule 01.04.2010
comment
stackoverflow.com/questions/1943433/   -  person Milen A. Radev    schedule 01.04.2010
comment
возможный дубликат имитации функции MySQL group_concat в SQL Server?   -  person ntalbs    schedule 10.02.2015
comment
Я думаю, что лучший ответ - это еще один вопрос: stackoverflow.com/a/47638417/243233   -  person Jus12    schedule 05.12.2017


Ответы (7)


Вероятно, это хорошая отправная точка (только версия 8.4+):

SELECT id_field, array_agg(value_field1), array_agg(value_field2)
FROM data_table
GROUP BY id_field

array_agg возвращает массив, но вы можете преобразовать его в текст и при необходимости отредактируйте (см. пояснения ниже).

До версии 8.4 вы должны определить его самостоятельно перед использованием:

CREATE AGGREGATE array_agg (anyelement)
(
    sfunc = array_append,
    stype = anyarray,
    initcond = '{}'
);

(перефразировано из документации PostgreSQL)

Разъяснения:

  • Результатом преобразования массива в текст является то, что результирующая строка начинается и заканчивается фигурными скобками. Эти скобки необходимо удалить каким-либо способом, если они не нужны.
  • Преобразование ANYARRAY в TEXT лучше всего имитирует вывод CSV, поскольку элементы, содержащие встроенные запятые, заключаются в двойные кавычки при выводе в стандартном стиле CSV. Ни array_to_string (), ни string_agg () (функция "group_concat", добавленная в 9.1) не помещают в кавычки строки со встроенными запятыми, что приводит к неправильному количеству элементов в итоговом списке.
  • Новая функция 9.1 string_agg () НЕ преобразует сначала внутренние результаты в ТЕКСТ. Таким образом, «string_agg (value_field)» вызовет ошибку, если value_field является целым числом. "string_agg (value_field :: text)" будет обязательным. Для метода array_agg () требуется только одно приведение после агрегирования (а не приведение для каждого значения).
person Matthew Wood    schedule 01.04.2010
comment
А в 9.0 у вас будет listagg () - person Scott Bailey; 01.04.2010
comment
Чтобы получить CSV, запрос должен иметь следующий вид: SELECT id_field, array_to_string (array_agg (value_field1), ','), array_to_string (array_agg (value_field2), ',') FROM data_table GROUP BY id_field - person Nux; 16.02.2012
comment
Здесь вы не можете использовать array_to_string во всех случаях. Если ваше value_field содержит встроенную запятую, полученный CSV неверен. Использование array_agg () и приведение к TEXT правильно помещают строки в кавычки со встроенными запятыми. Единственное предостережение заключается в том, что он также включает в себя начальную и конечную фигурные скобки, поэтому мое утверждение и редактирование по мере необходимости. Я отредактирую, чтобы прояснить этот момент. - person Matthew Wood; 22.02.2012
comment
К вашему сведению: вот ссылка на документы по array_agg в 8.4 - person Michael Rusch; 23.04.2014

Начиная с версии 9.0 это стало еще проще:

SELECT id, 
       string_agg(some_column, ',')
FROM the_table
GROUP BY id
person a_horse_with_no_name    schedule 10.01.2012
comment
Обратите внимание, что синтаксис также позволяет указать порядок значений в строке (или массиве, используя array_agg), например. string_agg(some_column, ',' ORDER BY some_column) или даже string_agg(surname || ', ' || forename, '; ' ORDER BY surname, forename) - person IMSoP; 16.05.2013
comment
Замечательно, что distinct работает со string_agg, поэтому можно использовать string_agg(distinct some_solumn, ',') - person arun; 04.07.2018
comment
Обратите внимание, что вам может потребоваться преобразовать значение столбца в TEXT, если оно не является строковым значением (например, uuid). Это будет выглядеть как string_agg(some_column::text, ',') - person Kendall; 11.09.2019
comment
Если тип столбца целочисленный, не забудьте преобразовать или использовать concat (column, '') для неявного преобразования. - person Takman; 01.10.2020
comment
PS, string_agg (value, ',') можно использовать, только если value является строкой. Например, если value является целым числом, value необходимо преобразовать в строку типа value::character varying - person ZenithS; 25.11.2020

SELECT array_to_string(array(SELECT a FROM b),', ');

Также подойдет.

person genobis    schedule 17.12.2010
comment
Можно ли сделать что-то вроде этого комментария, где вы агрегируете в определенном порядке ? Как бы вы справились с группировкой по одному столбцу и упорядочиванием по другому (например, для объединения переменных в одном наборе продольных данных)? - person Michael A; 08.01.2015

Попробуйте вот так:

select field1, array_to_string(array_agg(field2), ',')
from table1
group by field1;
person max_spy    schedule 11.01.2014

и версия для работы с типом массива:

select
  array_to_string(
    array(select distinct unnest(zip_codes) from table),
    ', '
);
person Sławomir Lenart    schedule 30.01.2019
comment
Повторяющийся ответ, @max_spy сказал то же самое пять лет назад - person Emil Vikström; 06.02.2019
comment
@ EmilVikström: у вас есть право ошибаться, но читайте внимательно. Это не только другое, но я привел пример, который работает с типом массива - например, zip_codes равняется character varying(5)[]. Кроме того, я подтвердил, что для моей цели - unnest необходим, иначе вы увидите ERROR: cannot accumulate arrays of different dimensionality. - person Sławomir Lenart; 06.02.2019

Мое предложение в postgresql

SELECT cpf || ';' || nome || ';' || telefone  
FROM (
      SELECT cpf
            ,nome
            ,STRING_AGG(CONCAT_WS( ';' , DDD_1, TELEFONE_1),';') AS telefone 
      FROM (
            SELECT DISTINCT * 
            FROM temp_bd 
            ORDER BY cpf DESC ) AS y
      GROUP BY 1,2 ) AS x   
person Lucas Cabral    schedule 31.10.2018
comment
Почему вы делаете ORDER BY во внутреннем запросе? Все равно заказ не потеряется? - person mypetlion; 31.10.2018

Надеюсь, что ниже запрос Oracle будет работать.

Select First_column,LISTAGG(second_column,',') 
    WITHIN GROUP (ORDER BY second_column) as Sec_column, 
    LISTAGG(third_column,',') 
    WITHIN GROUP (ORDER BY second_column) as thrd_column 
FROM tablename 
GROUP BY first_column
person kiruba    schedule 22.12.2019
comment
Я тестировал его на rextester.com/l/postgresql_online_compiler и не работал: 42883: function listagg ( текст, неизвестно, текст) не существует - person Manuel Romeiro; 04.02.2020
comment
Oracle имеет другой синтаксис и функции, чем postgres. - person Herman J. Radtke III; 05.02.2020