Ответ 1
Существует встроенная функция string_agg(), которая делает то, что вы хотите, но вы специально требуете, чтобы ее называли group_concat для совместимости с MySQL. К сожалению, string_agg() использует внутренний тип данных для накопления (предположительно, чтобы избежать копирования всего буфера на каждом добавлении, я не смотрел на источник, хотя), и я не нашел способ объявить SQL-aggrerate, идентичный string_agg ().
Определение функции group_concat() также не будет работать, так как pg должно быть осведомлено о том, что это агрегат, а не функция с совокупностью, скрытой внутри, которая не работает. Такая функция будет работать по одной строке за раз: любая совокупность внутри будет просто агрегировать одну строку и вернуть ее без изменений...
Таким образом, этот код будет накапливать элементы в массиве, а затем добавлять разделители "," с помощью array_to_string. Я буду использовать объявление array_agg() (прежде чем оно станет встроенным) в качестве модели и просто добавит функцию finalizer, которая преобразует агрегированный массив в текст.
CREATE OR REPLACE FUNCTION _group_concat_finalize(anyarray)
RETURNS text AS $$
SELECT array_to_string($1,',')
$$ IMMUTABLE LANGUAGE SQL;
CREATE AGGREGATE group_concat(anyelement) (
SFUNC=array_append,
STYPE=anyarray,
FFUNC=_group_concat_finalize,
INITCOND='{}'
);
SELECT group_concat(x) FROM foo;
Приятно, что он должен работать нормально для любого типа, без хлопот, благодаря родовым типам "anyarray" и "anyelement".
Я бы предположил, что это будет медленнее, чем string_agg(), если string_agg действительно не позволяет скопировать весь массив агрегации на каждом добавлении. Это должно иметь значение только в том случае, если количество строк, которые будут сгруппированы в каждый набор, велико. В этом случае вы, вероятно, можете потратить минуту на редактирование SQL-запроса;)