[sql] PostgreSQL ‘group by’쿼리에서 문자열 필드의 문자열을 연결하는 방법은 무엇입니까?

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

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 을 수행하는 내장 함수가 있습니다.



답변

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 $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가이 메일 링리스트 post에서 제안한 가장 간단한 사용자 정의 구현 은 내장 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이 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;


답변

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

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 () 함수를 추가하여 열을 배열로 롤업 할 수 있습니다. 그런 다음 응용 프로그램 코드에서 사용하거나 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;