Oracle에서 여러 행의 열 값을 연결하는 SQL 쿼리


169

여러 행의 열 값을 연결하기 위해 SQL을 구성 할 수 있습니까?

다음은 예입니다.

표 A

PID
ㅏ
비
씨

표 B

PID 시퀀스 설명

1 가지고
2 좋은
3 일
B 1 좋은 일.
C 1 예
우리가 할 수있는 C 2 
C 3 할 
C 4이 작품!

SQL의 출력은 다음과 같아야합니다.

PID 설명
A 좋은 하루 되세요.
B : 잘 했어.
C : 우리는이 일을 할 수 있습니다!

따라서 기본적으로 출력 테이블의 설명 열은 테이블 B의 SEQ 값을 연결 한 것입니까?

SQL에 대한 도움이 필요하십니까?


예를 들면 다음과 같습니다. halisway.blogspot.com/2006/08/…
Andomar

제발 봐 이 솔루션 . 도움이 될 것입니다.
Jineesh Uvantavida

답변:


237

사용중인 버전에 따라 몇 가지 방법이 있습니다 . 문자열 집계 기술에 대한 Oracle 설명서를 참조하십시오 . 가장 일반적인 방법은 다음을 사용하는 것입니다 LISTAGG.

SELECT pid, LISTAGG(Desc, ' ') WITHIN GROUP (ORDER BY seq) AS description
FROM B GROUP BY pid;

그런 다음에 가입 A밖으로 선택하는 pids당신이 원하는.

참고 : 기본적 LISTAGG으로 VARCHAR2열 에서만 올바르게 작동합니다 .


2
Oracle 10g에 wm_concat ()을 사용하면 쉼표로 구분 된 시퀀스 번호의 오름차순으로 텍스트를 연결합니다. 내림차순으로 다른 것을 구분할 수 있습니까?
jagamot

19

XMLAGG11.2 이전 버전에서 작동 하는 기능 도 있습니다 . OracleWM_CONCAT문서화하지 않고 지원하지 않기 때문에 프로덕션 시스템에서는 사용하지 않는 것이 좋습니다.

함께 XMLAGG사용하면 다음을 수행 할 수 있습니다 :

SELECT XMLAGG(XMLELEMENT(E,ename||',')).EXTRACT('//text()') "Result" 
FROM employee_names

이것이하는 일은

  • 테이블 의 ename열 값 (쉼표로 연결)을 employee_namesxml 요소 (태그 E 포함)에 넣습니다.
  • 이 텍스트를 추출
  • XML 집계 (연결)
  • 결과 열을 "결과"호출

XMLAGG는 Oracle 12.2에서 작동합니다. 또한 XLMAGG를 사용하면 LISTAGG의 최종 길이 때문에 매우 긴 문자열을 연결할 수 있습니다.
Marco

13

SQL 모델 절에서 :

SQL> select pid
  2       , ltrim(sentence) sentence
  3    from ( select pid
  4                , seq
  5                , sentence
  6             from b
  7            model
  8                  partition by (pid)
  9                  dimension by (seq)
 10                  measures (descr,cast(null as varchar2(100)) as sentence)
 11                  ( sentence[any] order by seq desc
 12                    = descr[cv()] || ' ' || sentence[cv()+1]
 13                  )
 14         )
 15   where seq = 1
 16  /

P SENTENCE
- ---------------------------------------------------------------------------
A Have a nice day
B Nice Work.
C Yes we can do this work!

3 rows selected.

나는 이것에 대해 여기에 썼습니다 . OTN 스레드 링크를 따라 가면 성능 비교를 포함하여 더 많은 것을 찾을 수 있습니다.



8

대부분의 답변에서 알 수 있듯이 LISTAGG확실한 옵션입니다. 그러나 한 가지 성가신 측면 LISTAGG은 연결된 문자열의 총 길이가 4000자를 초과하면 ( VARCHAR2SQL 제한 ) 아래 오류가 발생하여 Oracle 버전에서 12.1까지 관리하기가 어렵다는 것입니다

ORA-01489 : 캐릭터 라인 연결의 결과가 너무 깁니다

12cR2에 추가 된 새로운 기능은의 ON OVERFLOW조항입니다 LISTAGG. 이 절을 포함하는 쿼리는 다음과 같습니다.

SELECT pid, LISTAGG(Desc, ' ' on overflow truncate) WITHIN GROUP (ORDER BY seq) AS desc
FROM B GROUP BY pid;

위의 결과는 출력을 4000 자로 제한하지만 ORA-01489오류 는 발생 하지 않습니다 .

다음은 추가 ON OVERFLOW조항 옵션 중 일부입니다 .

  • ON OVERFLOW TRUNCATE 'Contd..' : 'Contd..'문자열 끝에 표시 됩니다 (기본값은 ...).
  • ON OVERFLOW TRUNCATE '' : 종료 문자열없이 4000자를 표시합니다.
  • ON OVERFLOW TRUNCATE WITH COUNT: 종료 문자 뒤의 총 문자 수를 표시합니다. 예 :- ' ...(5512)'
  • ON OVERFLOW ERROR: 오류 LISTAGG와 함께 실패 할 것으로 예상되는 경우 ORA-01489(어쨌든 기본값입니다).

6

Oracle 9i (또는 이전)를 사용하여이 문제를 해결해야하는 경우 LISTAGG를 사용할 수 없으므로 SYS_CONNECT_BY_PATH를 사용해야합니다.

OP에 응답하기 위해 다음 쿼리는 테이블 A의 PID를 표시하고 테이블 B의 모든 DESC 열을 연결합니다.

SELECT pid, SUBSTR (MAX (SYS_CONNECT_BY_PATH (description, ', ')), 3) all_descriptions
FROM (
       SELECT ROW_NUMBER () OVER (PARTITION BY pid ORDER BY pid, seq) rnum, pid, description
       FROM (
              SELECT a.pid, seq, description
              FROM table_a a, table_b b
              WHERE a.pid = b.pid(+)
             )
      )
START WITH rnum = 1
CONNECT BY PRIOR rnum = rnum - 1 AND PRIOR pid = pid
GROUP BY pid
ORDER BY pid;

키와 값이 모두 하나의 테이블에 포함되어있는 경우도 있습니다. 테이블 A가없고 테이블 B 만 존재하는 경우 다음 쿼리를 사용할 수 있습니다.

SELECT pid, SUBSTR (MAX (SYS_CONNECT_BY_PATH (description, ', ')), 3) all_descriptions
FROM (
       SELECT ROW_NUMBER () OVER (PARTITION BY pid ORDER BY pid, seq) rnum, pid, description
       FROM (
              SELECT pid, seq, description
              FROM table_b
             )
      )
START WITH rnum = 1
CONNECT BY PRIOR rnum = rnum - 1 AND PRIOR pid = pid
GROUP BY pid
ORDER BY pid;

원하는대로 모든 값을 다시 정렬 할 수 있습니다. 개별 연결 설명은 PARTITION BY 절에서 재정렬 될 수 있으며 PID 목록은 최종 ORDER BY 절에서 재정렬 될 수 있습니다.


또는 전체 테이블의 모든 값을 하나의 행으로 연결하려는 경우가 있습니다.

여기서 핵심 아이디어는 설명 그룹을 연결하기 위해 인공 값을 사용하는 것입니다.

다음 쿼리에서는 상수 문자열 '1'이 사용되지만 모든 값이 작동합니다.

SELECT SUBSTR (MAX (SYS_CONNECT_BY_PATH (description, ', ')), 3) all_descriptions
FROM (
       SELECT ROW_NUMBER () OVER (PARTITION BY unique_id ORDER BY pid, seq) rnum, description
       FROM (
              SELECT '1' unique_id, b.pid, b.seq, b.description
              FROM table_b b
             )
      )
START WITH rnum = 1
CONNECT BY PRIOR rnum = rnum - 1;

연결된 개별 설명은 PARTITION BY 절에서 순서를 바꿀 수 있습니다.

이 페이지의 다른 답변들도이 매우 유용한 참고 자료를 언급했습니다 : https://oracle-base.com/articles/misc/string-aggregation-techniques


3
  1. 정렬이 필수 일 경우 LISTAGG가 최상의 성능을 제공합니다 (00 : 00 : 05.85)

    SELECT pid, LISTAGG(Desc, ' ') WITHIN GROUP (ORDER BY seq) AS description FROM B GROUP BY pid;

  2. COLLECT는 정렬이 필요없는 경우 최고의 성능을 제공합니다 (00 : 00 : 02.90).

    SELECT pid, TO_STRING(CAST(COLLECT(Desc) AS varchar2_ntt)) AS Vals FROM B GROUP BY pid;

  3. 주문시 수집 속도가 약간 느립니다 (00 : 00 : 07.08) :

    SELECT pid, TO_STRING(CAST(COLLECT(Desc ORDER BY Desc) AS varchar2_ntt)) AS Vals FROM B GROUP BY pid;

다른 모든 기술은 느 렸습니다.


1
답을 자세히 설명하면 도움이 될 것입니다.
Jon Surrell

John, l 기사에서 반복하고 싶지 않았지만 간단히 결과는 다음과 같습니다. 1. 정렬이 필수 인 경우 LISTAGG가 최상의 성능을 제공합니다 (00 : 00 : 05.85) 2. 정렬이 아닌 경우 COLLECT가 최상의 성능을 제공합니다 필요 (00 : 00 : 02.90) : SELECT pid, TO_STRING (CAST (COLLECT AS AS varchar2_ntt)) AS Vals FROM B GROUP BY pid; 순서를 갖는 수집은 조금 느리다 (00 : 00 : 07.08) : SELECT pid, TO_STRING (CAST (COLLECT (Desc ORDER BY Desc) AS varchar2_ntt))) AS Vals FROM B GROUP BY pid; 다른 모든 기술은 느 렸습니다.
Misho

1
관련 정보를 포함하도록 답변을 편집하면됩니다.
Jon Surrell

편집이 너무 늦어서 다시 추가 한 것입니다. 죄송합니다. 여기에 새로 와서 막 시작했습니다.
Misho

1

선택 쿼리를 실행하기 전에 다음을 실행하십시오.

SET SERVEROUT ON SIZE 6000

SELECT XMLAGG(XMLELEMENT(E,SUPLR_SUPLR_ID||',')).EXTRACT('//text()') "SUPPLIER" 
FROM SUPPLIERS;

-1

이 코드를 사용해보십시오 :

 SELECT XMLAGG(XMLELEMENT(E,fieldname||',')).EXTRACT('//text()') "FieldNames"
    FROM FIELD_MASTER
    WHERE FIELD_ID > 10 AND FIELD_AREA != 'NEBRASKA';

-3

연결하려는 위치를 선택하고 SQL 함수를 호출하십시오.

예를 들면 다음과 같습니다.

select PID, dbo.MyConcat(PID)
   from TableA;

그런 다음 SQL 함수의 경우 :

Function MyConcat(@PID varchar(10))
returns varchar(1000)
as
begin

declare @x varchar(1000);

select @x = isnull(@x +',', @x, @x +',') + Desc
  from TableB
    where PID = @PID;

return @x;

end

함수 헤더 구문이 잘못되었을 수 있지만 원칙이 작동합니다.


이것은 Oracle에 유효하지 않습니다
a_horse_with_no_name
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.