SQL JOIN의 종류와 각각에 대해 설명해주세요.

김상욱·2024년 12월 14일

SQL JOIN의 종류와 각각에 대해 설명해주세요.

INNER JOIN

두 테이블 간의 공통 컬럼을 기준으로 일치하는 데이터만 반환.
조건을 만족하는 행만 결과에 포함하고 일치하지 않은 데이터는 제외.

SELECT A.column1, B.column2
FROM TableA A
INNER JOIN TableB B
ON A.common_column = B.common_column;

LEFT OUTER JOIN (LEFT JOIN)

왼쪽 테이블의 모든 데이터와 오른쪾 테이블에서 조건에 맞는 데이터를 반환합니다. 오른쪽 테이블에 일치하는 데이터가 없으면 NULL로 채움.

  • 왼쪽 테이블의 모든 데이터가 결과에 포함
  • 오른쪽 테이블에 매칭되지 않은 데이터는 NULL로 표시
SELECT A.column1, B.column2
FROM TableA A
LEFT JOIN TableB B
ON A.common_column = B.common_column;

RIGHT OUTER JOIN (RIGHT JOIN)

오른쪽 테이블의 모든 데이터와 왼쪽 테이블에서 조건에 맞는 데이터를 반환. 왼쪽 테이블에 일치하는 데이터가 없으면 NULL로 채움.

  • 오른쪽 테이블의 모든 데이터가 결과에 포함.
  • 왼쪽 테이블에 매칭되지 않는 데이터는 NULL로 표시.
SELECT A.column1, B.column2
FROM TableA A
RIGHT JOIN TableB B
ON A.common_column = B.common_column;

FULL OUTER JOIN

두 데이터의 모든 데이터를 반환. 조건에 맞지 않는 경우 NULL로 표시.

  • 두 테이블의 모든 데이터가 결과에 포함
  • 일치하지 않는 데이터는 각각 NULL로 표시
SELECT A.column1, B.column2
FROM TableA A
FULL OUTER JOIN TableB B
ON A.common_column = B.common_column;

CROSS JOIN

두 테이블의 모든 행의 조합(데카르트 곱)을 반환

  • 조건이 없으며, 두 테이블의 모든 가능한 조합을 생성
  • 행 수는 두 테이블의 행 수의 곱
SELECT A.column1, B.column2
FROM TableA A
CROSS JOIN TableB B;

SELF JOIN

같은 테이블을 기준으로 조인합니다. 테이블에 별칭(Alias)을 사용하여 두 개의 다른 테이블처럼 조작합니다.

  • 테이블 간의 계층 구조를 표현하거나 비교 연산을 수행할 때 유용.
SELECT A.column1, B.column2
FROM TableA A
INNER JOIN TableA B
ON A.common_column = B.common_column;

신입 또는 취준생 Java, Spring 백엔드 개발자가 SQL JOIN에 대해 실습한다면, 다음과 같은 실습을 통해 데이터베이스와 JOIN의 실제 사용 사례를 경험할 수 있습니다. 각각의 JOIN 유형에 대해 이해를 돕는 단계적 실습을 제안합니다.


실습 준비

  1. 데이터베이스 준비

    • 간단한 관계형 데이터베이스 스키마를 생성합니다. 예를 들어:
      • Employees 테이블: 직원 정보
      • Departments 테이블: 부서 정보
      • Projects 테이블: 프로젝트 정보
      • Employee_Projects 테이블: 직원과 프로젝트 간의 관계
    CREATE TABLE Employees (
        EmployeeID INT PRIMARY KEY,
        Name VARCHAR(50),
        DepartmentID INT
    );
    
    CREATE TABLE Departments (
        DepartmentID INT PRIMARY KEY,
        DepartmentName VARCHAR(50)
    );
    
    CREATE TABLE Projects (
        ProjectID INT PRIMARY KEY,
        ProjectName VARCHAR(50)
    );
    
    CREATE TABLE Employee_Projects (
        EmployeeID INT,
        ProjectID INT,
        PRIMARY KEY (EmployeeID, ProjectID),
        FOREIGN KEY (EmployeeID) REFERENCES Employees(EmployeeID),
        FOREIGN KEY (ProjectID) REFERENCES Projects(ProjectID)
    );
  2. 샘플 데이터 삽입

    INSERT INTO Employees VALUES (1, 'Alice', 1), (2, 'Bob', 2), (3, 'Charlie', NULL);
    INSERT INTO Departments VALUES (1, 'HR'), (2, 'Engineering');
    INSERT INTO Projects VALUES (1, 'Project A'), (2, 'Project B');
    INSERT INTO Employee_Projects VALUES (1, 1), (2, 2);
  3. Spring 환경 설정

    • Spring Boot 프로젝트를 생성하고 JPA/Hibernate 또는 MyBatis를 설정합니다.
    • 데이터베이스 연결을 위해 application.properties 또는 application.yml 파일에 데이터베이스 정보를 입력합니다.

실습: JOIN 유형별 구현

각 JOIN을 이해하고 활용할 수 있도록 간단한 쿼리를 작성하고, 이를 Java + Spring 환경에서 실행하는 실습을 진행합니다.

1. INNER JOIN

  • 목표: 직원과 부서 이름을 함께 출력.
  • SQL 쿼리:
    SELECT e.Name, d.DepartmentName
    FROM Employees e
    INNER JOIN Departments d ON e.DepartmentID = d.DepartmentID;
  • Spring 실습:
    • JPA Repository 또는 MyBatis Mapper를 작성합니다.
    @Query("SELECT e.name, d.departmentName FROM Employee e JOIN Department d ON e.departmentId = d.id")
    List<Object[]> findEmployeeWithDepartment();

2. LEFT OUTER JOIN

  • 목표: 부서가 없는 직원도 포함하여 출력.
  • SQL 쿼리:
    SELECT e.Name, d.DepartmentName
    FROM Employees e
    LEFT JOIN Departments d ON e.DepartmentID = d.DepartmentID;
  • Spring 실습:
    @Query("SELECT e.name, d.departmentName FROM Employee e LEFT JOIN Department d ON e.departmentId = d.id")
    List<Object[]> findAllEmployeesWithDepartments();

3. RIGHT OUTER JOIN

  • 목표: 직원이 없는 부서도 포함하여 출력.
  • SQL 쿼리:
    SELECT e.Name, d.DepartmentName
    FROM Employees e
    RIGHT JOIN Departments d ON e.DepartmentID = d.DepartmentID;
  • Spring 실습:
    @Query("SELECT e.name, d.departmentName FROM Employee e RIGHT JOIN Department d ON e.departmentId = d.id")
    List<Object[]> findAllDepartmentsWithEmployees();

4. FULL OUTER JOIN

  • 목표: 모든 직원과 모든 부서를 출력 (매칭되지 않는 데이터 포함).
  • SQL 쿼리 (MySQL은 FULL OUTER JOIN 미지원, UNION으로 대체):
    SELECT e.Name, d.DepartmentName
    FROM Employees e
    LEFT JOIN Departments d ON e.DepartmentID = d.DepartmentID
    UNION
    SELECT e.Name, d.DepartmentName
    FROM Employees e
    RIGHT JOIN Departments d ON e.DepartmentID = d.DepartmentID;
  • Spring 실습:
    @Query("SELECT e.name, d.departmentName " +
           "FROM Employee e LEFT JOIN Department d ON e.departmentId = d.id " +
           "UNION " +
           "SELECT e.name, d.departmentName " +
           "FROM Employee e RIGHT JOIN Department d ON e.departmentId = d.id")
    List<Object[]> findAllEmployeesAndDepartments();

5. CROSS JOIN

  • 목표: 모든 직원과 프로젝트의 조합 출력.
  • SQL 쿼리:
    SELECT e.Name, p.ProjectName
    FROM Employees e
    CROSS JOIN Projects p;
  • Spring 실습:
    @Query("SELECT e.name, p.projectName FROM Employee e CROSS JOIN Project p")
    List<Object[]> findAllEmployeeProjectCombinations();

6. SELF JOIN

  • 목표: 한 직원과 해당 직원의 상사 관계 출력 (예제 테이블에 ManagerID 추가 필요).
  • SQL 쿼리:
    SELECT e1.Name AS Employee, e2.Name AS Manager
    FROM Employees e1
    INNER JOIN Employees e2 ON e1.ManagerID = e2.EmployeeID;
  • Spring 실습:
    @Query("SELECT e1.name, e2.name " +
           "FROM Employee e1 JOIN Employee e2 ON e1.managerId = e2.id")
    List<Object[]> findEmployeesWithManagers();

확장 실습 아이디어

  1. 페이징 처리

    • 데이터를 많이 추가한 뒤, Spring Data JPA의 Pageable을 활용하여 페이징 처리된 결과를 반환합니다.
  2. 필터 추가

    • 사용자 입력을 받아 특정 조건에 맞는 데이터를 조회합니다. 예를 들어:
      • 특정 부서의 직원 조회
      • 특정 프로젝트에 참여하는 직원만 조회
  3. JOIN 결과 활용

    • JOIN 결과를 DTO로 매핑하여 REST API로 반환하는 기능을 구현합니다.
    • 예: EmployeeWithDepartmentDTO에 데이터를 매핑.
  4. 테스트 작성

    • JUnit을 사용해 각 JOIN 쿼리에 대한 테스트 케이스 작성.
    • 테스트 데이터 삽입 후 결과 검증.

실습 진행 시 주의할 점

  • 테이블 설계: 테이블 간 관계 (1:1, 1:N, N:M)를 명확히 이해하고 설계합니다.
  • 데이터 무결성: 외래 키 제약 조건을 활용하여 데이터 무결성을 유지합니다.
  • SQL 튜닝: JOIN을 사용할 때 쿼리 성능이 중요한 경우, 인덱스를 적절히 설정합니다.

이런 실습을 통해 JOIN의 개념을 코드로 체득하고, Spring과 연동하여 실제 프로젝트에서 어떻게 활용하는지 이해할 수 있습니다.

0개의 댓글