我们可以在 PostgreSQL 中定义一个 GROUP_CONCAT 函数吗?

Can we define a GROUP_CONCAT function in PostgreSQL?

我的遗留数据库有几行 SQL 代码,其中包含 GROUP_CONCAT 语句,如:

SELECT SUM(age), GROUP_CONCAT(sal) FROM Users;

在 PostgreSQL 中,我可以做同样的事情:

SELECT SUM(age), string_agg(sal, ', ') FROM Users;

我想尽可能多地使用旧的 SQL。所以我需要定义一个内部调用string_aggGROUP_CONCAT函数。这可能吗?

编辑:链接的问题无关!

我的问题是"How to define a function called group_concat?"。链接的问题说 "How can we do something equivalent to group concat (without defining a new function)?"。 None 的答案,也符合我的要求。

所选答案正确!值得庆幸的是,它在关闭之前得到了回答。

是的,这是可能的。看看 https://github.com/2ndQuadrant/mysqlcompat/blob/master/sql_bits/aggregate.sql 已经完成的地方,例如:

-- GROUP_CONCAT()
-- Note: only supports the comma separator
-- Note: For DISTINCT and ORDER BY a subquery is required
CREATE OR REPLACE FUNCTION _group_concat(text, text)
RETURNS text AS $$
  SELECT CASE
    WHEN  IS NULL THEN 
    WHEN  IS NULL THEN 
    ELSE  operator(pg_catalog.||) ',' operator(pg_catalog.||) 
  END
$$ IMMUTABLE LANGUAGE SQL;

CREATE AGGREGATE group_concat (
    BASETYPE = text,
    SFUNC = _group_concat,
    STYPE = text
);

有一个 string_agg() 内置函数可以满足您的需求,但您特别要求将其命名为 group_concat 以实现 MySQL 兼容性。不幸的是, string_agg() 使用内部数据类型进行累积(大概是为了避免在每次追加时复制整个缓冲区,不过我没有查看源代码)而且我没有找到声明 SQL 与 string_agg() 相同。

定义 group_concat() 函数也不起作用,因为必须让 pg 知道它是一个聚合,而不是一个内部隐藏了聚合的函数,后者不起作用。这样的函数将一次对一行进行操作:内部的任何聚合只会聚合一行并且return它不变...

因此,这段代码会将元素累加到一个数组中,然后用array_to_string加上“,”分隔符。我将使用 array_agg() 声明(在它成为内置函数之前)作为模型,并简单地添加一个终结函数,它将聚合数组转换为文本。

CREATE OR REPLACE FUNCTION _group_concat_finalize(anyarray)
RETURNS text AS $$
    SELECT array_to_string(,',')
$$ 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 查询 ;)

http://sqlfiddle.com/#!17/c452d/1