PostgreSQL '그룹별' 쿼리에서 문자열 필드의 문자열을 연결하는 방법은 무엇입니까?

StackOverflow https://stackoverflow.com/questions/43870

문제

쿼리를 통해 그룹 내의 필드 문자열을 연결하는 방법을 찾고 있습니다.예를 들어 다음과 같은 테이블이 있습니다.

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에는 이 작업을 수행하는 내장 함수가 있습니다. 그룹_연결

도움이 되었습니까?

해결책

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_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 $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;

다른 팁

Postgres 내장 배열 함수를 사용하는 것은 어떻습니까?적어도 8.4에서는 다음과 같이 즉시 작동합니다.

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

PostgreSQL 9.0부터 다음과 같은 집계 함수를 사용할 수 있습니다. string_agg.새 SQL은 다음과 같아야 합니다.

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

나는 몇 가지 검색 후에 답변을 찾았기 때문에 답변에 대한 공로가 없다고 주장합니다.

내가 몰랐던 것은 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;

이미 언급했듯이 자신만의 집계 함수를 만드는 것이 옳은 일입니다.내 연결 집계 함수는 다음과 같습니다. 세부 사항은 프랑스어로):

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

8.4로 업그레이드하려는 경우 다음 최신 공지 목록 조각이 흥미로울 수 있습니다.

8.4가 매우 효율적인 기본 원본이 나올 때까지, PostgreSQL 문서에 array_accum () 함수를 추가하여 모든 열을 배열로 롤업하기 위해 Application Code에서 사용할 수 있거나 Array_to_string ()과 형식으로 결합 할 수 있습니다. 목록으로 :

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

8.4 개발 문서에 연결하고 싶지만 아직 이 기능이 나열되지 않은 것 같습니다.

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;

문자열 연결의 사용자 정의 집계 함수 사용에 대해 다시 한 번 설명합니다.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

이 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;

사용 STRING_AGG 에 대한 기능 포스트그레SQL 그리고 구글 빅쿼리 SQL:

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

PostgreSQL 9.0 이상 버전에 따르면 string_agg라는 집계 함수를 사용할 수 있습니다.새 SQL은 다음과 같아야 합니다.

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

포맷 기능을 사용할 수도 있습니다.또한 텍스트, 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

저는 Jetbrains Rider를 사용하고 있는데 위 예제의 결과를 JSON으로 모두 래핑하는 것처럼 보여서 다시 실행하기 위해 복사하는 것이 번거로웠습니다.이렇게 하면 실행하기 더 쉬운 단일 문으로 결합됩니다.

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

string_agg가 지원되지 않는 Amazon Redshift를 사용하는 경우 listagg를 사용해 보십시오.

SELECT company_id, listagg(EMPLOYEE, ', ') as employees
FROM EMPLOYEE_table
GROUP BY company_id;
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top