如何连接 PostgreSQL 中字符串字段的字符串“group by” 询问?

发布于 2024-07-04 22:26:11 字数 785 浏览 6 评论 0原文

我正在寻找一种通过查询连接组内字段字符串的方法。 例如,我有一个表:

IDCOMPANY_IDEMPLOYEE
11Anna
21Bill
32Carol
42Dave

,我想按 company_id 进行分组以获得类似:

COMPANY_IDEMPLOYEE
1Anna, Bill
2Carol, Dave

有一个内置的-in mySQL 中的函数来执行此操作 group_concat

I am looking for a way to concatenate the strings of a field within a group by query. So for example, I have a table:

IDCOMPANY_IDEMPLOYEE
11Anna
21Bill
32Carol
42Dave

and I wanted to group by company_id to get something like:

COMPANY_IDEMPLOYEE
1Anna, Bill
2Carol, Dave

There is a built-in function in mySQL to do this group_concat

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(14

左岸枫 2024-07-11 22:26:11

我正在使用 Jetbrains Rider,从上面的示例中复制结果来重新执行是一件很麻烦的事情,因为它似乎将所有内容都包装在 JSON 中。 这将它们连接成一个更容易运行的语句

select string_agg('drop table if exists "' || tablename || '" cascade', ';') 
from pg_tables where schemaname != $pg_catalog$ and tableName like $rm_%$

I'm using Jetbrains Rider and it was a hassle copying the results from above examples to re-execute because it seemed to wrap it all in JSON. This joins them into a single statement that was easier to run

select string_agg('drop table if exists "' || tablename || '" cascade', ';') 
from pg_tables where schemaname != $pg_catalog$ and tableName like $rm_%$
黄昏下泛黄的笔记 2024-07-11 22:26:11

您还可以使用格式化功能。 它还可以自行隐式处理 text、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

You can also use format function. Which can also implicitly take care of type conversion of text, int, etc by itself.

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
携余温的黄昏 2024-07-11 22:26:11

根据 PostgreSQL 9.0 及以上版本,您可以使用名为 string_agg 的聚合函数。 您的新 SQL 应该如下所示:

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

According to version PostgreSQL 9.0 and above you can use the aggregate function called string_agg. Your new SQL should look something like this:

SELECT company_id, string_agg(employee, ', ')
    FROM mytable GROUP BY company_id;
路还长,别太狂 2024-07-11 22:26:11

如果您使用的是不支持 string_agg 的 Amazon Redshift,请尝试使用 listagg。

SELECT company_id, listagg(EMPLOYEE, ', ') as employees
FROM EMPLOYEE_table
GROUP BY company_id;

If you are on Amazon Redshift, where string_agg is not supported, try using listagg.

SELECT company_id, listagg(EMPLOYEE, ', ') as employees
FROM EMPLOYEE_table
GROUP BY company_id;
深白境迁sunset 2024-07-11 22:26:11

我发现这个 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;

I found this PostgreSQL documentation helpful: http://www.postgresql.org/docs/8.0/interactive/functions-conditional.html.

In my case, I sought plain SQL to concatenate a field with brackets around it, if the field is not empty.

select itemid, 
  CASE 
    itemdescription WHEN '' THEN itemname 
    ELSE itemname || ' (' || itemdescription || ')' 
  END 
from items;
遥远的她 2024-07-11 22:26:11

PostgreSQL<使用STRING_AGG函数/a> 和 Google BigQuery SQL

SELECT company_id, STRING_AGG(employee, ', ')
FROM employees
GROUP BY company_id;

Use STRING_AGG function for PostgreSQL and Google BigQuery SQL:

SELECT company_id, STRING_AGG(employee, ', ')
FROM employees
GROUP BY company_id;
陌上芳菲 2024-07-11 22:26:11

再次关注字符串连接的自定义聚合函数的使用:您需要记住 select 语句将以任何顺序放置行,因此您需要在 select 中执行子操作>from 语句带有 order by 子句,然后是外部 select 带有 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

Following yet again on the use of a custom aggregate function of string concatenation: you need to remember that the select statement will place rows in any order, so you will need to do a sub select in the from statement with an order by clause, and then an outer select with a group by clause to aggregate the strings, thus:

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
半边脸i 2024-07-11 22:26:11

遵循 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;

Following up on Kev's answer, using the Postgres docs:

First, create an array of the elements, then use the built-in array_to_string function.

CREATE AGGREGATE array_accum (anyelement)
(
 sfunc = array_append,
 stype = anyarray,
 initcond = '{}'
);

select array_to_string(array_accum(name),'|') from table group by id;
岁吢 2024-07-11 22:26:11

如果您要升级到 8.4,您可能会对这个最新的公告列表片段感兴趣:

直到 8.4 发布
超高效原生的,可以添加
array_accum() 函数在
用于滚动的 PostgreSQL 文档
将任意列放入数组中,可以
然后由应用程序代码使用,或者
与 array_to_string() 结合使用
将其格式化为列表:

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

我会链接到 8.4 开发文档,但他们似乎还没有列出此功能。

This latest announcement list snippet might be of interest if you'll be upgrading to 8.4:

Until 8.4 comes out with a
super-effient native one, you can add
the array_accum() function in the
PostgreSQL documentation for rolling
up any column into an array, which can
then be used by application code, or
combined with array_to_string() to
format it as a list:

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

I'd link to the 8.4 development docs but they don't seem to list this feature yet.

是你 2024-07-11 22:26:11

正如已经提到的,创建自己的聚合函数是正确的做法。 这是我的串联聚合函数(您可以找到法语详细信息):)

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

As already mentioned, creating your own aggregate function is the right thing to do. Here is my concatenation aggregate function (you can find details in French):

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

);

And then use it as:

SELECT company_id, concatenate(employee) AS employees FROM ...
停顿的约定 2024-07-11 22:26:11

我不承认这个答案,因为我在一番搜索后找到了它:

我不知道的是 PostgreSQL 允许您使用 创建聚合

PostgreSQL 列表中的这篇文章展示了创建一个函数来执行所需操作是多么简单:

CREATE AGGREGATE textcat_all(
  basetype    = text,
  sfunc       = textcat,
  stype       = text,
  initcond    = ''
);

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

I claim no credit for the answer because I found it after some searching:

What I didn't know is that PostgreSQL allows you to define your own aggregate functions with CREATE AGGREGATE

This post on the PostgreSQL list shows how trivial it is to create a function to do what's required:

CREATE AGGREGATE textcat_all(
  basetype    = text,
  sfunc       = textcat,
  stype       = text,
  initcond    = ''
);

SELECT company_id, textcat_all(employee || ', ')
FROM mytable
GROUP BY company_id;
本宫微胖 2024-07-11 22:26:11

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

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

As from PostgreSQL 9.0 you can use the aggregate function called string_agg. Your new SQL should look something like this:

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

羁〃客ぐ 2024-07-11 22:26:11

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

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

How about using Postgres built-in array functions? At least on 8.4 this works out of the box:

SELECT company_id, array_to_string(array_agg(employee), ',')
FROM mytable
GROUP BY company_id;
听闻余生 2024-07-11 22:26:11

PostgreSQL 9.0 或更高版本:

现代 Postgres(自 2010 年起)具有 string_agg(expression, delimiter) 函数将完全满足请求者的要求:

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

Postgres 9 还添加了指定 ORDER BY 子句的功能在任何聚合表达式中; 否则,您必须对所有结果进行排序或处理未定义的顺序。 所以你现在可以写:

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

PostgreSQL 8.4.x:

请注意,对 Postgres 8.4 的支持于 2014 年结束,因此您可能应该出于比字符串聚合更重要的原因进行升级。

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;

PostgreSQL 8.3.x 及更早版本:

最初提出这个问题时,没有内置的聚合函数来连接字符串。 最简单的自定义实现(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;

PostgreSQL 9.0 or later:

Modern Postgres (since 2010) has the string_agg(expression, delimiter) function which will do exactly what the asker was looking for:

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

Postgres 9 also added the ability to specify an ORDER BY clause in any aggregate expression; otherwise you have to order all your results or deal with an undefined order. So you can now write:

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

PostgreSQL 8.4.x:

Please note that support for Postgres 8.4 ended in 2014, so you should probably upgrade for more important reasons than string aggregation.

PostgreSQL 8.4 (in 2009) introduced the aggregate function array_agg(expression) which collects the values in an array. Then array_to_string() can be used to give the desired result:

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

PostgreSQL 8.3.x and older:

When this question was originally posed, there was no built-in aggregate function to concatenate strings. The simplest custom implementation (suggested by Vajda Gabo in this mailing list post, among many others) is to use the built-in textcat function:

CREATE AGGREGATE textcat_all(
  basetype    = text,
  sfunc       = textcat,
  stype       = text,
  initcond    = ''
);

Here is the CREATE AGGREGATE documentation.

This simply glues all the strings together, with no separator. In order to get a ", " inserted in between them without having it at the end, you might want to make your own concatenation function and substitute it for the "textcat" above. Here is one I put together and tested on 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;

This version will output a comma even if the value in the row is null or empty, so you get output like this:

a, b, c, , e, , g

If you would prefer to remove extra commas to output this:

a, b, c, e, g

Then add an ELSIF check to the function like this:

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;
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文