SQL - 조인(JOIN)
조인(JOIN)
조인
은 데이터베이스에서 두 개 이상의 테이블을 관련된 컬럼을 기반으로 결합하여 하나의 테이블로 합치는 메커니즘을 의미합니다.
일반적으로 행들은 기본키(PK)와 외래키(FK)의 연관관계에 의해 조인이 성립됩니다. 하지만 PK, FK의 관계가 없더라도 논리적인 값들의 연관관계만으로도 조인이 성립할 수 있습니다.
동등 조인(Equi Join)
동등 조인
은 일반적으로 “조인 키”라고 하는 일치하는 열을 기반으로 두 테이블을 결합하는 조인 작업 유형입니다.
특히 동등 조인은 조인 키가 정확히 일치하는 두 테이블의 행만 반환합니다. 즉, 조인 키 값이 두 테이블에서 동일한 두 테이블의 모든 열을 포함하는 새 테이블을 생성합니다.
예를 들어 “ORDERS”와 “EMPLOYEES”라는 두 개의 테이블이 있다고 가정합니다. 각 주문에는 “EMPLOYEES” 테이블의 직원에 해당하는 EMPLOYEE_ID가 있습니다. 모든 주문 및 관련 고객 정보를 찾으려면 두 테이블의 EMPLOYEE_ID 컬럼에서 동등 조인을 수행하면 됩니다.
아래는 예제 데이터 입니다.
EMPLOYEES
EMPLOYEE_ID | FIRST_NAME | LAST_NAME |
---|---|---|
1 | John | Smith |
2 | Jane | Doe |
3 | Bob | Johnson |
4 | Sarah | Lee |
ORDERS
ORDER_ID | EMPLOYEE_ID | ORDER_DATE |
---|---|---|
1001 | 1 | 2023-01-01 |
1002 | 2 | 2023-01-15 |
1003 | 3 | 2023-02-01 |
1004 | 4 | 2023-02-15 |
두 테이블 모두에 존재하는 EMPLOYEE_ID 컬럼을 통해 동등 조인을 수행할 수 있습니다.
동등 조인 예제
SELECT EMPLOYEES.FIRST_NAME,
EMPLOYEES.LAST_NAME,
ORDERS.ORDER_ID,
TO_CHAR(ORDERS.ORDER_DATE, 'YYYY-MM-DD') ORDER_DATE
FROM EMPLOYEES, ORDERS
WHERE EMPLOYEES.EMPLOYEE_ID = ORDERS.EMPLOYEE_ID;
결과는 다음과 같습니다.
동등 조인 결과
LAST_NAME | FIRST_NAME | ORDER_ID | ORDER_DATE |
---|---|---|---|
Smith | John | 1001 | 2023-01-01 |
Doe | Jane | 1002 | 2023-01-15 |
Johnson | Bob | 1003 | 2023-02-01 |
Lee | Sarah | 1004 | 2023-02-15 |
비동등 조인(Non Equi Join)
비동등 조인
은 조인 조건이 같지 않은 비교 연산자를 기반으로 하는 SQL의 조인 유형입니다. 동등 연산자(=)가 아닌 다른 연산자를 사용하여 조인을 수행합니다.
대부분 비동등 조인을 수행할 수 있지만, 설계상의 이유로 수행이 불가능할 수도 있습니다.
아래는 예제 데이터 입니다.
CUSTOMERS
CUSTOMER_ID | NAME | AMOUNT |
---|---|---|
1 | John | 450000 |
2 | Jane | 150000 |
3 | Bob | 600000 |
4 | Sarah | 300000 |
GRADE
GRADE | LOW | HIGH |
---|---|---|
1 | 100000 | 199999 |
2 | 200000 | 299999 |
3 | 300000 | 399999 |
4 | 400000 | 499999 |
5 | 500000 | 599999 |
6 | 600000 | 699999 |
고객의 총 구매액에 대하여 등급을 구하고 싶다면 다음과 같은 비동등 조인 쿼리를 작성할 수 있습니다.
비동등 조인 예제
SELECT CUSTOMERS.NAME,
CUSTOMERS.AMOUNT,
GRADE.GRADE
FROM CUSTOMERS, GRADE
WHERE CUSTOMERS.AMOUNT BETWEEN GRADE.LOW AND GRADE.HIGH;
결과는 다음과 같습니다.
비동등 조인 결과
NAME | AMOUNT | GRADE |
---|---|---|
John | 450000 | 4 |
Jane | 150000 | 1 |
Bob | 600000 | 6 |
Sarah | 300000 | 3 |
표준 조인
표준 조인
은 ANSI/ISO 표준에서 규정한 조인입니다.
표준 조인에는 내부 조인(Inner Join)
, 외부 조인(Outer Join)
, 크로스 조인(Cross Join)
, 자연 조인(Natural Join)
이 있습니다.
내부 조인(Inner Join)
내부 조인은 조인 조건에서 동일한 값이 있는 행만 반환하는 조인입니다.
내부 조인 문법
SELECT 컬럼명
FROM 테이블1
INNER JOIN 테이블2
ON 조건절;
다음과 같은 예제 데이터가 있다고 가정합시다.
EMPLOYEES
EMPLOYEE_ID | FIRST_NAME | LAST_NAME |
---|---|---|
1 | John | Smith |
2 | Jane | Doe |
3 | Bob | Johnson |
4 | Sarah | Lee |
ORDERS
ORDER_ID | EMPLOYEE_ID | ORDER_DATE |
---|---|---|
1001 | 1 | 2023-01-01 |
1002 | 2 | 2023-01-15 |
1003 | 1 | 2023-02-01 |
1004 | 5 | 2023-02-15 |
EMPLOYEES 테이블에 있는 직원 중 주문 이력이 있는 직원을 확인하고 싶다면 다음과 같이 쿼리를 작성하면 됩니다.
내부 조인 예제
SELECT EMPLOYEES.EMPLOYEE_ID,
EMPLOYEES.FIRST_NAME,
EMPLOYEES.LAST_NAME,
TO_CHAR(ORDERS.ORDER_DATE, 'YYYY-MM-DD') ORDER_DATE
FROM EMPLOYEES
INNER JOIN ORDERS
ON EMPLOYEES.EMPLOYEE_ID = ORDERS.EMPLOYEE_ID;
결과는 다음과 같습니다.
내부 조인 결과
EMPLOYEE_ID | FIRST_NAME | LAST_NAME | ORDER_DATE |
---|---|---|---|
1 | John | Smith | 2023-01-01 |
2 | Jane | Doe | 2023-01-15 |
1 | John | Smith | 2023-02-01 |
오라클의 경우 다음과 같이 내부 조인 쿼리를 작성할 수 있습니다.
오라클 내부 조인 예제
SELECT EMPLOYEES.EMPLOYEE_ID,
EMPLOYEES.FIRST_NAME,
EMPLOYEES.LAST_NAME,
TO_CHAR(ORDERS.ORDER_DATE, 'YYYY-MM-DD') ORDER_DATE
FROM EMPLOYEES, ORDERS
WHERE EMPLOYEES.EMPLOYEE_ID = ORDERS.EMPLOYEE_ID;
외부 조인(Outer Join)
외부 조인
은 조인 조건에서 동일한 값이 없더라도 행을 반환하는 조인입니다.
외부 조인은 왼쪽 테이블을 기준으로 외부 조인을 수행하는 Left Outer Join
, 오른쪽 테이블을 기준으로 외부 조인을 수행하는 Right Outer Join
, 양쪽 테이블을 기준으로 외부 조인을 수행하는 Full Outer Join
이 있습니다.
Left Outer Join
Left Outer Join
은 왼쪽 테이블을 기준으로 외부 조인을 수행합니다.
Left Outer Join 예제
SELECT EMPLOYEES.EMPLOYEE_ID,
EMPLOYEES.FIRST_NAME,
EMPLOYEES.LAST_NAME,
TO_CHAR(ORDERS.ORDER_DATE, 'YYYY-MM-DD') ORDER_DATE
FROM EMPLOYEES
LEFT OUTER JOIN ORDERS
ON EMPLOYEES.EMPLOYEE_ID = ORDERS.EMPLOYEE_ID;
결과는 다음과 같습니다.
Left Outer Join 결과
EMPLOYEE_ID | FIRST_NAME | LAST_NAME | ORDER_DATE |
---|---|---|---|
1 | John | Smith | 2023-01-01 |
2 | Jane | Doe | 2023-01-15 |
1 | John | Smith | 2023-02-01 |
4 | Sarah | Lee | |
3 | Bob | Johnson |
오라클의 경우 다음과 같이 Left Outer Join 쿼리를 작성할 수 있습니다.
오라클 Left Outer Join 예제
SELECT EMPLOYEES.EMPLOYEE_ID,
EMPLOYEES.FIRST_NAME,
EMPLOYEES.LAST_NAME,
TO_CHAR(ORDERS.ORDER_DATE, 'YYYY-MM-DD') ORDER_DATE
FROM EMPLOYEES, ORDERS
WHERE EMPLOYEES.EMPLOYEE_ID = ORDERS.EMPLOYEE_ID(+);
Right Outer Join
Right Outer Join
은 오른쪽 테이블을 기준으로 외부 조인을 수행합니다.
Right Outer Join 예제
SELECT EMPLOYEES.EMPLOYEE_ID,
EMPLOYEES.FIRST_NAME,
EMPLOYEES.LAST_NAME,
TO_CHAR(ORDERS.ORDER_DATE, 'YYYY-MM-DD') ORDER_DATE
FROM EMPLOYEES
RIGHT OUTER JOIN ORDERS
ON EMPLOYEES.EMPLOYEE_ID = ORDERS.EMPLOYEE_ID;
결과는 다음과 같습니다.
Right Outer Join 결과
EMPLOYEE_ID | FIRST_NAME | LAST_NAME | ORDER_DATE |
---|---|---|---|
1 | John | Smith | 2023-01-01 |
1 | John | Smith | 2023-02-01 |
2 | Jane | Doe | 2023-01-15 |
2023-02-15 |
오라클의 경우 다음과 같이 Left Outer Join 쿼리를 작성할 수 있습니다.
오라클 Right Outer Join 예제
SELECT EMPLOYEES.EMPLOYEE_ID,
EMPLOYEES.FIRST_NAME,
EMPLOYEES.LAST_NAME,
TO_CHAR(ORDERS.ORDER_DATE, 'YYYY-MM-DD') ORDER_DATE
FROM EMPLOYEES, ORDERS
WHERE EMPLOYEES.EMPLOYEE_ID(+) = ORDERS.EMPLOYEE_ID;
Full Outer Join
Full Outer Join
은 오른쪽 테이블을 기준으로 외부 조인을 수행합니다.
Full Outer Join 예제
SELECT EMPLOYEES.EMPLOYEE_ID,
EMPLOYEES.FIRST_NAME,
EMPLOYEES.LAST_NAME,
TO_CHAR(ORDERS.ORDER_DATE, 'YYYY-MM-DD') ORDER_DATE
FROM EMPLOYEES
FULL OUTER JOIN ORDERS
ON EMPLOYEES.EMPLOYEE_ID = ORDERS.EMPLOYEE_ID;
결과는 다음과 같습니다.
Full Outer Join 결과
EMPLOYEE_ID | FIRST_NAME | LAST_NAME | ORDER_DATE |
---|---|---|---|
1 | John | Smith | 2023-01-01 |
2 | Jane | Doe | 2023-01-15 |
1 | John | Smith | 2023-02-01 |
2023-02-15 | |||
4 | Sarah | Lee | |
3 | Bob | Johnson |
오라클의 경우 Full Outer Join 문법이 없습니다.
크로스 조인(Cross Join)
크로스 조인
은 조인 조건 없이 모든 데이터의 조합을 나타내는 조인입니다.
크로스 조인 문법
SELECT 컬럼명
FROM 테이블1
CROSS JOIN 테이블2;
크로스 조인 예제
SELECT EMPLOYEES.EMPLOYEE_ID,
EMPLOYEES.FIRST_NAME,
EMPLOYEES.LAST_NAME,
TO_CHAR(ORDERS.ORDER_DATE, 'YYYY-MM-DD') ORDER_DATE
FROM EMPLOYEES
CROSS JOIN ORDERS;
결과는 다음과 같습니다.
크로스 조인 결과
EMPLOYEE_ID | FIRST_NAME | LAST_NAME | ORDER_DATE |
---|---|---|---|
1 | John | Smith | 2023-01-01 |
1 | John | Smith | 2023-01-15 |
1 | John | Smith | 2023-02-01 |
1 | John | Smith | 2023-02-15 |
2 | Jane | Doe | 2023-01-01 |
2 | Jane | Doe | 2023-01-15 |
2 | Jane | Doe | 2023-02-01 |
2 | Jane | Doe | 2023-02-15 |
3 | Bob | Johnson | 2023-01-01 |
3 | Bob | Johnson | 2023-01-15 |
3 | Bob | Johnson | 2023-02-01 |
3 | Bob | Johnson | 2023-02-15 |
4 | Sarah | Lee | 2023-01-01 |
4 | Sarah | Lee | 2023-01-15 |
4 | Sarah | Lee | 2023-02-01 |
4 | Sarah | Lee | 2023-02-15 |
자연 조인(Natural Join)
자연 조인
은 서로 다른 테이블에서 동일한 이름을 갖는 컬럼에 대하여 자동으로 동등 조인을 수행합니다.
자연 조인 문법
SELECT 컬럼명
FROM 테이블1
NATURAL JOIN 테이블2;
자연 조인 예제
SELECT EMPLOYEE_ID,
EMPLOYEES.FIRST_NAME,
EMPLOYEES.LAST_NAME,
TO_CHAR(ORDERS.ORDER_DATE, 'YYYY-MM-DD') ORDER_DATE
FROM EMPLOYEES
NATURAL JOIN ORDERS;
EMPLOYEES 테이블과 ORDERS 테이블에서 동일한 이름을 가지는 EMPLOYEE_ID 컬럼은 별명(Alias)를 주지 않았습니다. 이때 Natural Join을 사용하면 EMPLOYEE_ID 컬럼을 기준으로 내부 조인을 수행하게 됩니다.
결과는 다음과 같이 내부 조인의 결과와 같음을 확인할 수 있습니다.
자연 조인 결과
EMPLOYEE_ID | FIRST_NAME | LAST_NAME | ORDER_DATE |
---|---|---|---|
1 | John | Smith | 2023-01-01 |
2 | Jane | Doe | 2023-01-15 |
1 | John | Smith | 2023-02-01 |
내부 조인에서도 ON 조건절 대신에 USING
조건절을 사용한다면 자연 조인처럼 별명(Alias) 없이 컬럼을 지정할 수 있습니다.
USING 조건절 예제
SELECT EMPLOYEE_ID,
EMPLOYEES.FIRST_NAME,
EMPLOYEES.LAST_NAME,
TO_CHAR(ORDERS.ORDER_DATE, 'YYYY-MM-DD') ORDER_DATE
FROM EMPLOYEES
INNER JOIN ORDERS
USING (EMPLOYEE_ID);