当前位置:  开发笔记 > 后端 > 正文

如何通过'查询连接PostgreSQL'组中的字符串字段的字符串?

如何解决《如何通过'查询连接PostgreSQL'组中的字符串字段的字符串?》经验,为你挑选了8个好方法。

我正在寻找一种通过查询连接组内字段的字符串的方法.例如,我有一张桌子:

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> Neall..:

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 对于9.0之前的版本:

如果有人遇到这个寻找9.0之前数据库的兼容垫片,可以实现string_aggORDER 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 $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
);

自定义变体(所有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;

即使行中的值为null或为空,此版本也将输出逗号,因此您将获得如下输出:

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;


"没有用于连接字符串的内置聚合函数" - 为什么不使用`array_to_string(array_agg(employee),',')`?
请注意,最新版本的Postgres还允许在聚合函数中使用`Order By`子句,例如`string_agg(employee,','Order By employee)`
PostgreSQL 9.0函数的+1.如果您需要关注9.0之前的版本,Markus的答案会更好.

2> 小智..:

如何使用Postgres内置数组函数?至少在8.4上这是开箱即用的:

SELECT company_id, array_to_string(array_agg(employee), ',')
FROM mytable
GROUP BY company_id;



3> dirbacke..:

从PostgreSQL 9.0开始,您可以使用名为string_agg的聚合函数.您的新SQL应该如下所示:

SELECT company_id, string_agg(employee, ', ')
FROM mytable
GROUP BY company_id;



4> Guy C..:

我对答案没有任何赞誉,因为我经过一番搜索后发现它:

我不知道的是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> bortzmeyer..:

如前所述,创建自己的聚合函数是正确的做法.这是我的串联聚合函数(您可以在法语中找到详细信息):

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 = ''

);

然后将其用作:

SELECT company_id, concatenate(employee) AS employees FROM ...



6> Kev..:

如果您要升级到8.4,可能会对此最新公告列表摘录感兴趣:

直到8.4出现一个超高效的本机,你可以在PostgreSQL文档中添加array_accum()函数,将任何列汇总到一个数组中,然后可以由应用程序代码使用,或者与array_to_string()结合使用以格式化它作为一个清单:

http://www.postgresql.org/docs/current/static/xaggr.html

我将链接到8.4开发文档,但它们似乎还没有列出此功能.



7> 小智..:

跟进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;



8> 小智..:

再次使用字符串连接的自定义聚合函数:您需要记住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

推荐阅读
勤奋的瞌睡猪_715
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有