오라클 옆으로 붙이기 - olakeul yeop-eulo but-igi

JOIN과는 다르게 UNION처럼 그냥 데이터를 붙이고 싶을 때가 있다.

UNION은 2개의 테이블이 위아래로 붙는데 좌우로 붙이고 싶으면 어떻게 해야할까?

SELECT한 것을 다시 SELECT함으로써 해결할 수 있다.

SELECT
    (SELECT COUNT(idx)
     FROM MEMBER
     WHERE 1=1
     AND GRADE = 'A') AS VIP
  , (SELECT COUNT(idx)
     FROM MEMBER) AS TOTAL
;

결과 :

오라클 옆으로 붙이기 - olakeul yeop-eulo but-igi

1. LISTAGG 함수의 활용

오라클 쿼리를 실행하다보면 같은 조건을 가진 여러 행을 하나의 행으로 합치고 싶은 경우가 발생한다.

예를 들어 그림과 같은 테이블 데이터가 있다고 했을 때, 

오라클 옆으로 붙이기 - olakeul yeop-eulo but-igi

하나의 COUNTRY_ID (국가)에 있는 도시 종류를 한 눈에 보고싶다고 가정하자.

같은 COUNTRY_ID를 GROUP BY 처리하고,

그 GROUP에 해당하는 모든 행(ROW)을 한 행(ROW)으로 합쳐야한다.

이 때, 유용하게 쓸 수 있는 함수가 LISTAGG이다.

SELECT COUNTRY_ID, LISTAGG(CITY,',') WITHIN GROUP (ORDER BY CITY) AS 도시목록
FROM HR.LOCATIONS
GROUP BY COUNTRY_ID
ORDER BY COUNTRY_ID;

이 쿼리를 실행하면 아래와 같은 결과가 나온다.

오라클 옆으로 붙이기 - olakeul yeop-eulo but-igi

COUNTRY_ID로 GROUP BY를 하여,

여러 행이던 CITY 컬럼의 데이터를 한 ROW로 LISTAGG(LIST AGGREGATION) 해주는 것이다.

LISTAGG의 두번째 PARAMETER는 구분자로 위 쿼리에서는 ,을 사용했는데 다른 구분자로 활용 가능하다.

2. WM_CONCAT과의 차이점

11g 이전 버전에서는 WM_CONCAT이라는 함수를 사용했다.

SELECT COUNTRY_ID, WM_CONCAT(CITY) AS 도시목록
FROM HR.LOCATIONS
GROUP BY COUNTRY_ID
ORDER BY COUNTRY_ID;

10g 버전의 오라클이라면 위 쿼리도 앞선 LISTAGG와 유사하게 사용 가능하다.

다만, WM_CONCAT은 합친 ROW의 정렬이 안 된다는 단점이 있다.

LISTAGG는 사용시 WITHIN GROUP (ORDER BY {컬럼명}) 을 통해 정렬이 가능하지만,

WM_CONCAT은 정렬이 불가능하다.

11g 이후에는 공식적으로 지원하지 않으니 LISTAGG의 활용을 추천.

참고자료 : https://docs.oracle.com/cd/E11882_01/server.112/e41084/functions089.htm#SQLRF30030

LISTAGG

LISTAGG Syntax Description of the illustration ''listagg.gif'' See Also: "Analytic Functions" for information on syntax, semantics, and restrictions of the ORDER BY clause and OVER clause Purpose For a specified measure, LISTAGG orders data within each gro

docs.oracle.com

SQL

[SQL] 테이블 합치기 (JOIN / UNION)

'칼퇴족 김대리는 알고 나만 모르는 SQL, 10장'을 인용하였다 

오라클 옆으로 붙이기 - olakeul yeop-eulo but-igi

내부 조인

1. FROM / WHERE 를 사용

: 내부 조인은 두 테이블의 키값이 매칭될 경우 선택된 모든 열을 나타낸다

SELECT 테이블명1.열이름1, 테이블명2.열이름2 

FROM 테이블명1, 테이블명2

WHERE  테이블명1.KEY = 테이블명2.KEY;

2. INNER JOIN 을 사용

: INNER JOIN을 사용하면 두 테이블을 합칠 수 있다. ON 뒤에 두 테이블의 연결고리가 되는 키 값을 적어야 한다

SELECT 테이블명1.열이름1, 테이블명2.열이름2 

FROM 테이블명1 INNER JOIN 테이블명2

ON  테이블명1.KEY = 테이블명2.KEY;

Ex)

고객주소 테이블: ADDR

 CUST_ID

 HOME_ADDR1

 HOME_ADDR2

 5465

 서울시 강남구 역삼동 

 111-11

 2354

 서울시 종로구 공평동

 222-22

 5410

 서울시 중구 서소문동

 333-33

고객휴대폰 테이블: MOBILE

 CUST_ID

 MOBILE_NO

 5465

 010-1111-1111

 2354

 010-2222-2222

SELECT ADDR.*, MOBILE.MOBILE_NO 

FROM ADDR INNER JOIN MOBILE

ON  ADDR.CUST_ID = MOBILE.CUST_ID;

결과

 CUST_ID

 HOME_ADDR1

 HOME_ADDR2

 MOBILE_NO

 5465

 서울시 강남구 역삼동

 111-11

 010-1111-1111

 2354

 서울시 종로구 공평동

 222-22

 010-2222-2222

외부 조인

1. LEFT OUTER JOIN

: 왼쪽 테이블을 기준으로 조인하는 방법으로, OUTER를 생략해도 무방하다

SELECT 별칭.1열이름1, 별칭2.열이름2 

FROM 테이블명1 (AS) 별칭1 LEFT (OUTER) JOIN 테이블명2 (AS) 별칭2

ON  별칭1.KEY = 별칭2.KEY;

2. RIGHT OUTER JOIN

: 오른쪽 테이블을 기준으로 조인하는 방법으로, OUTER를 생략해도 무방하다

SELECT 별칭.1열이름1, 별칭2.열이름2 

FROM 테이블명1 (AS) 별칭1 RIGHT (OUTER) JOIN 테이블명2 (AS) 별칭2

ON  별칭1.KEY = 별칭2.KEY;

3. FULL OUTER JOIN

: 왼쪽과 오른쪽 테이블의 모든 행이 반환된다  

SELECT 별칭.1열이름1, 별칭2.열이름2 

FROM 테이블명1 (AS) 별칭1 FULL (OUTER) JOIN 테이블명2 (AS) 별칭2

ON  별칭1.KEY = 별칭2.KEY;

Ex)

고객주소 테이블1: ADDR1

CUST_ID

 HOME_ADDR1

 HOME_ADDR2

 5465

 서울시 강남구 역삼동 

 111-11

 2354

 서울시 종로구 공평동

 222-22

 5410

 서울시 중구 서소문동

 333-33

 6511

 서울시 송파구 문정동

  444-44

고객휴대폰 테이블1: MOBILE1

CUST_ID

 MOBILE_NO

 5465

 010-1111-1111

 2354

 010-2222-2222

 5410

 010-3333-3333

 5410

 010-7777-7777

 7979

 010-7979-7979

(LEFT OUTER JOIN)

SELECT TMP1.CUST_ID AS CUST_ID1, TMP1.HOME_ADDR1, TMP1.HOME_ADDR2,

               TMP2.CUST_ID AS CUST_ID2, TMP2.MOBILE_NO 

FROM ADDR1 AS TMP1

LEFT OUTER JOIN MOBILE1 AS TMP2 ON TMP1.CUST_ID = TMP2.CUST_ID;

결과 (CUST_ID가 6511인 고객의 MOBILE_NO는 NULL값으로 처리)

 CUST_ID1

 HOME_ADDR1

 HOME_ADDR2

 CUST_ID2

 MOBILE_NO

 5465

 서울시 강남구 역삼동

 111-11

 5465

 010-1111-1111

 2354

 서울시 종로구 공평동

 222-22

 2354

 010-2222-2222

 5410

 서울시 중구 서소문동

 333-33

 5410

 010-3333-3333

 5410

 서울시 중구 서소문동

 333-33

 5410

 010-7777-7777

 6511

 서울시 송파구 문정동

 444-44

(RIGHT OUTER JOIN)

SELECT TMP1.CUST_ID AS CUST_ID1, TMP1.HOME_ADDR1, TMP1.HOME_ADDR2,

               TMP2.CUST_ID AS CUST_ID2, TMP2.MOBILE_NO 

FROM ADDR1 AS TMP1

RIGHT OUTER JOIN MOBILE1 AS TMP2 ON TMP1.CUST_ID = TMP2.CUST_ID;

결과 

 CUST_ID1

 HOME_ADDR1

 HOME_ADDR2

 CUST_ID2

 MOBILE_NO

 5465

 서울시 강남구 역삼동

 111-11

 5465

 010-1111-1111

 2354

 서울시 종로구 공평동

 222-22

 2354

 010-2222-2222

 5410

 서울시 중구 서소문동

 333-33

 5410

 010-3333-3333

 5410

 서울시 중구 서소문동

 333-33

 5410

 010-7777-7777

 7979

  010-7979-7979

(FULL OUTER JOIN)

SELECT TMP1.CUST_ID AS CUST_ID1, TMP1.HOME_ADDR1, TMP1.HOME_ADDR2,

               TMP2.CUST_ID AS CUST_ID2, TMP2.MOBILE_NO 

FROM ADDR1 AS TMP1

FULL OUTER JOIN MOBILE1 AS TMP2 ON TMP1.CUST_ID = TMP2.CUST_ID;

결과

CUST_ID1

 HOME_ADDR1

 HOME_ADDR2

 CUST_ID2

 MOBILE_NO

 5465

 서울시 강남구 역삼동

 111-11

 5465

 010-1111-1111

 2354

 서울시 종로구 공평동

 222-22

 2354

 010-2222-2222

 5410

 서울시 중구 서소문동

 333-33

 5410

 010-3333-3333

 5410

 서울시 중구 서소문동

 333-33

 5410

 010-7777-7777

 6511

 서울시 송파구 문정동

 444-44

 7979

 010-7979-7979

UNION 연산자

1. UNION 연산자 사용

: UNION은 두 개 이상의 SELECT문의 행을 합치는 역할을 한다

SELECT 열이름1, 열이름2 FROM 테이블명1 WHERE 조건절

UNION

SELECT 열이름1, 열이름2 FROM 테이블명2 WHERE 조건절

ORDER BY 1;

2. UNION ALL 연산자 사용

UNION ALL 연산자는 두 개 이상의 SELECT문의 행을 합치는 역할을 한다. UNION 연산자와의 차이는 중복을 포함한 모든 값을 나타낸다는 것이다

SELECT 열이름1, 열이름2 FROM 테이블명1 WHERE 조건절

UNION ALL

SELECT 열이름1, 열이름2 FROM 테이블명2 WHERE 조건절

ORDER BY 1;

오라클 옆으로 붙이기 - olakeul yeop-eulo but-igi