Guy*_*y C 329 sql postgresql group-by string-aggregation
我正在寻找一种通过查询连接组内字段的字符串的方法.例如,我有一张桌子:
ID COMPANY_ID EMPLOYEE
1 1 Anna
2 1 Bill
3 2 Carol
4 2 Dave
Run Code Online (Sandbox Code Playgroud)
我想通过company_id分组得到类似的东西:
COMPANY_ID EMPLOYEE
1 Anna, Bill
2 Carol, Dave
Run Code Online (Sandbox Code Playgroud)
mySQL中有一个内置函数来执行这个group_concat
Nea*_*all 513
最新版本的Postgres(自2010年末以来)具有的string_agg(expression, delimiter)功能将完全满足问题的要求,甚至允许您指定分隔符字符串:
SELECT company_id, string_agg(employee, ', ')
FROM mytable
GROUP BY company_id;
Run Code Online (Sandbox Code Playgroud)
Postgres 9.0还添加了在任何聚合表达式中指定ORDER BY子句的功能; 否则,订单未定义.所以你现在可以写:
SELECT company_id, string_agg(employee, ', ' ORDER BY employee)
FROM mytable
GROUP BY company_id;
Run Code Online (Sandbox Code Playgroud)
或者确实:
SELECT string_agg(actor_name, ', ' ORDER BY first_appearance)
Run Code Online (Sandbox Code Playgroud)
PostgreSQL 8.4(2009年)引入了聚合函数array_agg(expression),它将值连接成一个数组.然后array_to_string()可以用来给出想要的结果:
SELECT company_id, array_to_string(array_agg(employee), ', ')
FROM mytable
GROUP BY company_id;
Run Code Online (Sandbox Code Playgroud)
string_agg 对于9.0之前的版本:如果有人遇到这个寻找9.0之前数据库的兼容垫片,可以实现string_agg除ORDER BY子句之外的所有内容.
因此,使用以下定义,这应该与9.x Postgres DB中的相同:
SELECT string_agg(name, '; ') AS semi_colon_separated_names FROM things;
Run Code Online (Sandbox Code Playgroud)
但这将是一个语法错误:
SELECT string_agg(name, '; ' ORDER BY name) AS semi_colon_separated_names FROM things;
--> ERROR: syntax error at or near "ORDER"
Run Code Online (Sandbox Code Playgroud)
在PostgreSQL 8.3上测试过.
CREATE FUNCTION string_agg_transfn(text, text, text)
RETURNS text AS
$$
BEGIN
IF $1 IS NULL THEN
RETURN $2;
ELSE
RETURN $1 || $3 || $2;
END IF;
END;
$$
LANGUAGE plpgsql IMMUTABLE
COST 1;
CREATE AGGREGATE string_agg(text, text) (
SFUNC=string_agg_transfn,
STYPE=text
);
Run Code Online (Sandbox Code Playgroud)
在9.0之前,没有内置的聚合函数来连接字符串.最简单的自定义实现(由Vajda Gabo在此邮件列表中提供,以及许多其他内容)是使用内置textcat函数(位于||运算符后面):
CREATE AGGREGATE textcat_all(
basetype = text,
sfunc = textcat,
stype = text,
initcond = ''
);
Run Code Online (Sandbox Code Playgroud)
这简单地将所有字符串粘合在一起,没有分隔符.为了在它们之间插入","而不在最后,它可能想要创建自己的连接函数并将其替换为上面的"textcat".这是我在8.3.12上放在一起测试的一个:
CREATE FUNCTION commacat(acc text, instr text) RETURNS text AS $$
BEGIN
IF acc IS NULL OR acc = '' THEN
RETURN instr;
ELSE
RETURN acc || ', ' || instr;
END IF;
END;
$$ LANGUAGE plpgsql;
Run Code Online (Sandbox Code Playgroud)
即使行中的值为null或为空,此版本也将输出逗号,因此您将获得如下输出:
a, b, c, , e, , g
Run Code Online (Sandbox Code Playgroud)
如果您希望删除额外的逗号来输出:
a, b, c, e, g
Run Code Online (Sandbox Code Playgroud)
然后ELSIF在函数中添加一个检查,如下所示:
CREATE FUNCTION commacat_ignore_nulls(acc text, instr text) RETURNS text AS $$
BEGIN
IF acc IS NULL OR acc = '' THEN
RETURN instr;
ELSIF instr IS NULL OR instr = '' THEN
RETURN acc;
ELSE
RETURN acc || ', ' || instr;
END IF;
END;
$$ LANGUAGE plpgsql;
Run Code Online (Sandbox Code Playgroud)
小智 93
如何使用Postgres内置数组函数?至少在8.4上这是开箱即用的:
SELECT company_id, array_to_string(array_agg(employee), ',')
FROM mytable
GROUP BY company_id;
Run Code Online (Sandbox Code Playgroud)
dir*_*cke 18
从PostgreSQL 9.0开始,您可以使用名为string_agg的聚合函数.您的新SQL应该如下所示:
SELECT company_id, string_agg(employee, ', ')
FROM mytable
GROUP BY company_id;Run Code Online (Sandbox Code Playgroud)
Guy*_*y C 13
我对答案没有任何赞誉,因为我经过一番搜索后发现它:
我不知道的是PostgreSQL允许您使用CREATE AGGREGATE定义自己的聚合函数
PostgreSQL列表中的这篇文章显示了创建一个函数来执行所需操作是多么微不足道:
CREATE AGGREGATE textcat_all(
basetype = text,
sfunc = textcat,
stype = text,
initcond = ''
);
SELECT company_id, textcat_all(employee || ', ')
FROM mytable
GROUP BY company_id;
Run Code Online (Sandbox Code Playgroud)
如前所述,创建自己的聚合函数是正确的做法.这是我的串联聚合函数(您可以在法语中找到详细信息):
CREATE OR REPLACE FUNCTION concat2(text, text) RETURNS text AS '
SELECT CASE WHEN $1 IS NULL OR $1 = \'\' THEN $2
WHEN $2 IS NULL OR $2 = \'\' THEN $1
ELSE $1 || \' / \' || $2
END;
'
LANGUAGE SQL;
CREATE AGGREGATE concatenate (
sfunc = concat2,
basetype = text,
stype = text,
initcond = ''
Run Code Online (Sandbox Code Playgroud)
);
然后将其用作:
SELECT company_id, concatenate(employee) AS employees FROM ...
Run Code Online (Sandbox Code Playgroud)
如果您要升级到8.4,可能会对此最新公告列表摘录感兴趣:
直到8.4出现一个超高效的本机,你可以在PostgreSQL文档中添加array_accum()函数,将任何列汇总到一个数组中,然后可以由应用程序代码使用,或者与array_to_string()结合使用以格式化它作为一个清单:
我将链接到8.4开发文档,但它们似乎还没有列出此功能.
小智 5
跟进Kev的回答,使用Postgres文档:
首先,创建一个元素数组,然后使用内置array_to_string函数.
CREATE AGGREGATE array_accum (anyelement)
(
sfunc = array_append,
stype = anyarray,
initcond = '{}'
);
select array_to_string(array_accum(name),'|') from table group by id;
Run Code Online (Sandbox Code Playgroud)
小智 5
再次使用字符串连接的自定义聚合函数:您需要记住select语句将以任何顺序放置行,因此您需要在from语句中使用order by子句进行子选择,并且然后是一个带有group by子句的外部选择来聚合字符串,因此:
SELECT custom_aggregate(MY.special_strings)
FROM (SELECT special_strings, grouping_column
FROM a_table
ORDER BY ordering_column) MY
GROUP BY MY.grouping_column
Run Code Online (Sandbox Code Playgroud)
使用PostgreSQL和Google BigQuery SQLSTRING_AGG的函数:
SELECT company_id, STRING_AGG(employee, ', ')
FROM employees
GROUP BY company_id;
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
298988 次 |
| 最近记录: |