ID COMPANY_ID EMPLOYEE
1 1 Anna
2 1 Bill
3 2 Carol
4 2 Dave
,我想按company_id分组以得到类似的内容:
COMPANY_ID EMPLOYEE
1 Anna, Bill
2 Carol, Dave
mySQL中有一个内置函数可以执行此group_concat
#1 楼
PostgreSQL 9.0或更高版本:最新版本的Postgres(自2010年末开始)具有
string_agg(expression, delimiter)
函数,该函数可以完全满足问题的要求,甚至允许您指定分隔符字符串:SELECT company_id, string_agg(employee, ', ')
FROM mytable
GROUP BY company_id;
Postgres 9.0还添加了在任何聚合表达式中指定
ORDER BY
子句的功能;否则,顺序是不确定的。因此,您现在可以编写:SELECT company_id, string_agg(employee, ', ' ORDER BY employee)
FROM mytable
GROUP BY company_id;
或者确实是:
SELECT string_agg(actor_name, ', ' ORDER BY first_appearance)
PostgreSQL 8.4或更高版本:
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;
string_agg
(8.4版之前的版本):遇到此问题,寻找9.0之前版本的数据库的兼容性填充程序时,可以在
string_agg
中实现除ORDER BY
子句之外的所有内容。因此,使用以下定义,该功能应与9中的功能相同。 x Postgres DB:
SELECT string_agg(name, '; ') AS semi_colon_separated_names FROM things;
但这将是语法错误:
SELECT string_agg(name, '; ' ORDER BY name) AS semi_colon_separated_names FROM things;
--> ERROR: syntax error at or near "ORDER"
在PostgreSQL 8.3上测试。
CREATE FUNCTION string_agg_transfn(text, text, text)
RETURNS text AS
$$
BEGIN
IF IS NULL THEN
RETURN ;
ELSE
RETURN || || ;
END IF;
END;
$$
LANGUAGE plpgsql IMMUTABLE
COST 1;
CREATE AGGREGATE string_agg(text, text) (
SFUNC=string_agg_transfn,
STYPE=text
);
自定义变体(所有Postgres版本)
在9.0之前,没有内置的聚合函数来连接字符串。最简单的自定义实现(由Vajda Gabo在此邮件列表中的建议,以及许多其他建议)是使用内置的
textcat
函数(位于||
运算符后面):CREATE AGGREGATE textcat_all(
basetype = text,
sfunc = textcat,
stype = text,
initcond = ''
);
这是
CREATE AGGREGATE
文档。这只是将所有字符串粘在一起,没有分隔符。为了使它们之间没有插入“,”,您可能需要创建自己的串联函数,并将其替换为上面的“ 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;
即使行中的值为空或空,此版本也会输出逗号,因此您将获得如下输出:
a, b, c, , e, , g
如果您希望删除多余的逗号输出以下内容:
a, b, c, e, g
然后将
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;
评论
我不得不S&R varchar到文本(最新的pgsql稳定),但这很棒!
– Kev
08年11月18日在16:26
您只能使用SQL编写该函数,该函数易于安装(超级用户必须安装plpgsql)。参见我的帖子中的示例。
– Bortzmeyer
08年12月9日在19:55
“没有内置的聚合函数来连接字符串”-为什么不使用array_to_string(array_agg(employee),',')?
– pstanton
2011年9月1日,1:11
PostgreSQL 9.0函数的+1。如果您需要关注9.0之前的版本,Markus的答案会更好。
–布拉德·科赫(Brad Koch)
2011年11月4日在16:17
请注意,最新版本的Postgres还允许在聚合函数内使用Order By子句,例如string_agg(员工,','按员工订购)
–IMSoP
13年4月6日在11:58
#2 楼
如何使用Postgres内置数组函数?至少在8.4上可以立即使用:SELECT company_id, array_to_string(array_agg(employee), ',')
FROM mytable
GROUP BY company_id;
评论
遗憾的是,这对于Greenplum(v8.2)来说不起作用。 +1都一样
– ekkis
16年8月25日在17:35
在Greenplum 4.3.4.1(建立在PostgreSQL 8.2.15上)上,对我来说工作正常。
– PhilHibbs
17年5月31日在13:28
#3 楼
从PostgreSQL 9.0开始,您可以使用称为string_agg的聚合函数。您的新SQL应该看起来像这样:SELECT company_id, string_agg(employee, ', ')
FROM mytable
GROUP BY company_id;
#4 楼
我对这个答案不屑一顾,因为我经过一番搜索发现了它:我不知道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;
#5 楼
如前所述,创建自己的聚合函数是正确的事情。这是我的串联聚合函数(您可以在法语中找到详细信息):CREATE OR REPLACE FUNCTION concat2(text, text) RETURNS text AS '
SELECT CASE WHEN IS NULL OR = \'\' THEN
WHEN IS NULL OR = \'\' THEN
ELSE || \' / \' ||
END;
'
LANGUAGE SQL;
CREATE AGGREGATE concatenate (
sfunc = concat2,
basetype = text,
stype = text,
initcond = ''
);
然后将其用作:
SELECT company_id, concatenate(employee) AS employees FROM ...
#6 楼
如果您要升级到8.4,则可能需要关注最新的公告列表片段:在8.4发行具有
超级本机的版本之前,您可以添加
PostgreSQL文档中的array_accum()函数用于将任意列滚动到数组中,然后可以将其
供应用程序代码使用,或者
与array_to_string组合使用()格式化为列表:
http://www.postgresql.org/docs/current/static/xaggr.html
我已链接到8.4开发文档,但他们似乎还没有列出此功能。
#7 楼
使用Postgres文档跟踪Kev的答案:首先创建元素数组,然后使用内置的
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;
#8 楼
再次使用字符串连接的自定义聚合函数:您需要记住,select语句将以任何顺序放置行,因此您需要在from语句中使用order by子句进行子选择,并且然后使用带有group by子句的外部select来聚合字符串,因此: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
#9 楼
我发现此PostgreSQL文档很有帮助:http://www.postgresql.org/docs/8.0/interactive/functions-conditional.html。我的情况是,我寻求普通的SQL将字段与如果字段不为空,请用括号括起来。
select itemid,
CASE
itemdescription WHEN '' THEN itemname
ELSE itemname || ' (' || itemdescription || ')'
END
from items;
#10 楼
对PostgreSQL和Google BigQuery SQL使用STRING_AGG
函数:SELECT company_id, STRING_AGG(employee, ', ')
FROM employees
GROUP BY company_id;
#11 楼
根据PostgreSQL 9.0及更高版本,您可以使用称为string_agg的聚合函数。您的新SQL应该看起来像这样:SELECT company_id, string_agg(employee, ', ')
FROM mytable GROUP BY company_id;
#12 楼
您也可以使用格式化功能。它也可以隐式地处理文本,int等的类型转换。create or replace function concat_return_row_count(tbl_name text, column_name text, value int)
returns integer as $row_count$
declare
total integer;
begin
EXECUTE format('select count(*) from %s WHERE %s = %s', tbl_name, column_name, value) INTO total;
return total;
end;
$row_count$ language plpgsql;
postgres=# select concat_return_row_count('tbl_name','column_name',2); --2 is the value
评论
这与使用聚合来连接字符串值有什么关系?
– a_horse_with_no_name
18年8月30日在11:37
#13 楼
我使用的是Jetbrains Rider,复制上面示例的结果以重新执行很麻烦,因为它似乎都将其包装在JSON中。这使它们成为一个易于运行的语句select string_agg('drop table if exists "' || tablename || '" cascade', ';')
from pg_tables where schemaname != $$pg_catalog$$ and tableName like $$rm_%$$
#14 楼
如果您在不支持string_agg的Amazon Redshift上,请尝试使用listagg。SELECT company_id, listagg(EMPLOYEE, ', ') as employees
FROM EMPLOYEE_table
GROUP BY company_id;
评论
从技术上来说,MarkusDöring的答案更好。@ pstanton,Döring的答案仅适用于8.4及以下版本。
这个问题似乎更适合dba.stackexchange.com。
现在应该是有效的答案stackoverflow.com/a/47638417/243233