MySQL 공통 테이블 표현식 (CTE)

MySQLBeginner
지금 연습하기

소개

이 랩에서는 MySQL 에서 Common Table Expressions(CTE) 를 사용하는 방법을 배우게 됩니다. CTE 는 복잡한 쿼리를 논리적이고 읽기 쉬운 단계로 분할하여 단순화하는 데 도움이 됩니다. CTE 는 단일 SQL 문 내에서 참조할 수 있는 임시 명명된 결과 집합을 생성합니다.

먼저 데이터베이스를 설정하고 직원 데이터를 필터링하기 위한 간단한 CTE 를 생성합니다. 그런 다음 계층적 데이터 (예: 조직도) 를 처리하기 위해 재귀 CTE 를 탐색합니다. 마지막으로 CTE 를 테이블과 조인하여 더 고급 데이터 분석을 수행하는 방법을 배우게 됩니다.

이것은 가이드 실험입니다. 학습과 실습을 돕기 위한 단계별 지침을 제공합니다.각 단계를 완료하고 실무 경험을 쌓기 위해 지침을 주의 깊게 따르세요. 과거 데이터에 따르면, 이것은 초급 레벨의 실험이며 완료율은 100%입니다.학습자들로부터 92%의 긍정적인 리뷰율을 받았습니다.

데이터베이스 및 간단한 CTE 설정

이 첫 번째 단계에서는 데이터베이스 환경을 설정하고 간단한 Common Table Expression(CTE) 을 정의합니다. CTE 는 WITH 절을 사용하여 정의되며 단일 쿼리 기간 동안만 존재하는 임시 뷰 역할을 합니다. 이를 통해 복잡한 쿼리를 더 쉽게 읽고 관리할 수 있습니다.

먼저 데스크톱에서 터미널을 엽니다.

root 사용자로 MySQL 서버에 연결합니다. 이 랩 환경에서는 비밀번호 없이 sudo를 사용하여 연결할 수 있습니다.

sudo mysql -u root

연결되면 MySQL 프롬프트 (mysql>) 가 표시됩니다. 이제 labex_db라는 데이터베이스를 생성하고 해당 데이터베이스로 전환합니다.

CREATE DATABASE IF NOT EXISTS labex_db;
USE labex_db;

다음으로 employees 테이블을 생성하고 샘플 데이터를 삽입합니다. 이 테이블은 직원의 부서 및 급여를 포함한 기본 정보를 저장합니다.

CREATE TABLE IF NOT EXISTS employees (
    employee_id INT PRIMARY KEY,
    first_name VARCHAR(50),
    last_name VARCHAR(50),
    department VARCHAR(50),
    salary DECIMAL(10, 2)
);

INSERT INTO employees (employee_id, first_name, last_name, department, salary) VALUES
(1, 'John', 'Doe', 'Sales', 60000.00),
(2, 'Jane', 'Smith', 'Marketing', 75000.00),
(3, 'Robert', 'Jones', 'Sales', 55000.00),
(4, 'Emily', 'Brown', 'IT', 90000.00),
(5, 'Michael', 'Davis', 'Marketing', 70000.00);

이제 테이블이 준비되었으므로 'Sales' 부서의 직원만 선택하는 간단한 CTE 를 정의해 보겠습니다.

WITH SalesEmployees AS (
    SELECT employee_id, first_name, last_name, salary
    FROM employees
    WHERE department = 'Sales'
)
SELECT * FROM SalesEmployees;

이 쿼리를 자세히 살펴보겠습니다.

  • WITH SalesEmployees AS (...): SalesEmployees라는 CTE 를 정의합니다.
  • 괄호 안의 쿼리는 department가 'Sales'인 employees 테이블에서 직원을 선택합니다.
  • SELECT * FROM SalesEmployees;: 이는 임시 SalesEmployees 결과 집합에서 모든 데이터를 검색하는 기본 쿼리입니다.

Sales 부서의 직원만 나열하는 다음 출력이 표시되어야 합니다.

+-------------+------------+-----------+----------+
| employee_id | first_name | last_name | salary   |
+-------------+------------+-----------+----------+
|           1 | John       | Doe       | 60000.00 |
|           3 | Robert     | Jones     | 55000.00 |
+-------------+------------+-----------+----------+
2 rows in set (0.00 sec)

이는 첫 번째 CTE 가 올바르게 작동함을 확인합니다. 다음 단계를 위해 MySQL 셸에 계속 머물러 주십시오.

계층적 데이터를 위한 재귀 CTE 생성

재귀 CTE 는 조직도 또는 중첩된 카테고리와 같은 계층적 데이터를 쿼리하는 강력한 기능입니다. 재귀 CTE 는 트리와 같은 구조를 레벨별로 처리하기 위해 자체를 참조합니다. "앵커 멤버"(시작점) 와 "재귀 멤버"(반복) 로 구성됩니다.

이 단계에서는 직원 계층을 나타내는 테이블을 생성하고 재귀 CTE 를 사용하여 표시합니다.

먼저 MySQL 셸에 있는 동안 employee_hierarchy 테이블을 생성합니다. 이 테이블에는 다른 직원의 employee_id를 가리키는 manager_id가 포함되어 계층 구조를 만듭니다.

CREATE TABLE IF NOT EXISTS employee_hierarchy (
    employee_id INT PRIMARY KEY,
    employee_name VARCHAR(50),
    manager_id INT
);

INSERT INTO employee_hierarchy (employee_id, employee_name, manager_id) VALUES
(1, 'David', NULL),
(2, 'Emily', 1),
(3, 'Frank', 1),
(4, 'Grace', 2),
(5, 'Henry', 2),
(6, 'Ivy', 3),
(7, 'Jack', 3);

이 구조에서 'David'는 manager_idNULL이므로 최상위 관리자입니다.

이제 이 계층 구조를 탐색하기 위한 재귀 CTE 를 작성합니다. RECURSIVE 키워드가 필요합니다.

WITH RECURSIVE EmployeeHierarchyCTE AS (
    -- Anchor member: 최상위 관리자를 선택합니다.
    SELECT employee_id, employee_name, manager_id, 0 AS level
    FROM employee_hierarchy
    WHERE manager_id IS NULL

    UNION ALL

    -- Recursive member: 자체와 조인하여 하위 직원을 찾습니다.
    SELECT e.employee_id, e.employee_name, e.manager_id, h.level + 1
    FROM employee_hierarchy e
    INNER JOIN EmployeeHierarchyCTE h ON e.manager_id = h.employee_id
)
SELECT * FROM EmployeeHierarchyCTE ORDER BY level, employee_name;

이 쿼리를 분석해 보겠습니다.

  • 앵커 멤버: 첫 번째 SELECT 문은 계층 구조의 루트 ( manager_idNULL인 곳) 를 찾고 level 0 을 할당합니다.
  • 재귀 멤버: 두 번째 SELECT 문은 employee_hierarchy를 CTE 자체 (EmployeeHierarchyCTE) 와 조인합니다. CTE 에 이미 있는 employee_id와 일치하는 manager_id를 가진 모든 직원을 찾고 level을 증가시킵니다.
  • UNION ALL: 이 연산자는 앵커 멤버와 재귀 멤버의 결과를 결합합니다.

쿼리는 레벨이 있는 전체 조직도를 보여주는 다음 출력을 생성합니다.

+-------------+---------------+------------+-------+
| employee_id | employee_name | manager_id | level |
+-------------+---------------+------------+-------+
|           1 | David         |       NULL |     0 |
|           2 | Emily         |          1 |     1 |
|           3 | Frank         |          1 |     1 |
|           4 | Grace         |          2 |     2 |
|           5 | Henry         |          2 |     2 |
|           6 | Ivy           |          3 |     2 |
|           7 | Jack          |          3 |     2 |
+-------------+---------------+------------+-------+
7 rows in set (0.00 sec)

재귀 CTE 를 사용하여 계층적 데이터를 성공적으로 쿼리했습니다. 마지막 단계를 위해 MySQL 셸에 계속 머물러 주십시오.

CTE 와 테이블 조인

CTE 는 일반 테이블처럼 다른 테이블과 조인할 수 있습니다. 이는 CTE 에서 집계된 데이터를 다른 테이블의 상세 데이터와 결합하는 데 유용합니다. 이 단계에서는 부서별 평균 급여를 계산하는 CTE 를 생성한 다음 employees 테이블과 다시 조인합니다.

MySQL 셸에 있는 동안 다음 쿼리를 실행합니다. 이 쿼리는 AvgSalaryByDepartment라는 CTE 를 정의한 다음 employees 테이블과 조인합니다.

WITH AvgSalaryByDepartment AS (
    SELECT
        department,
        AVG(salary) AS avg_salary
    FROM employees
    GROUP BY department
)
SELECT
    e.employee_id,
    e.first_name,
    e.department,
    e.salary,
    a.avg_salary
FROM
    employees e
JOIN
    AvgSalaryByDepartment a ON e.department = a.department;

다음은 분석입니다.

  • AvgSalaryByDepartment CTE 는 각 부서의 평균 급여를 계산합니다.
  • 그런 다음 기본 쿼리는 employees 테이블 (별칭 e) 을 이 CTE(별칭 a) 와 department 열을 기준으로 조인합니다.
  • 이를 통해 각 직원의 급여를 해당 부서의 평균 급여 옆에 표시할 수 있습니다.

예상 출력은 다음과 같습니다.

+-------------+------------+------------+----------+--------------+
| employee_id | first_name | department | salary   | avg_salary   |
+-------------+------------+------------+----------+--------------+
|           1 | John       | Sales      | 60000.00 | 57500.000000 |
|           2 | Jane       | Marketing  | 75000.00 | 72500.000000 |
|           3 | Robert     | Sales      | 55000.00 | 57500.000000 |
|           4 | Emily      | IT         | 90000.00 | 90000.000000 |
|           5 | Michael    | Marketing  | 70000.00 | 72500.000000 |
+-------------+------------+------------+----------+--------------+
5 rows in set (0.00 sec)

결과를 수동으로 확인할 수 있습니다. 예를 들어 'Sales' 부서의 평균 급여는 (60000 + 55000) / 2 = 57500이며 이는 출력과 일치합니다. 이는 쿼리가 올바르게 작동함을 확인합니다.

CTE 와 테이블을 성공적으로 조인했습니다. 이제 MySQL 셸을 종료할 수 있습니다.

exit;

요약

이 실습에서는 MySQL 에서 공통 테이블 표현식 (CTE) 을 효과적으로 사용하는 방법을 배웠습니다. 데이터베이스와 테이블을 설정하는 것으로 시작하여 다양한 유형의 CTE 를 생성하는 과정을 진행했습니다.

다음과 같은 내용을 배웠습니다.

  • WITH 절을 사용하여 데이터를 필터링하고 쿼리 가독성을 향상시키는 간단한 CTE 정의
  • 테이블의 계층적 데이터를 탐색하고 표시하기 위한 재귀 CTE 생성
  • CTE 와 테이블을 조인하여 집계된 결과와 상세 행 수준 데이터를 결합하여 더 복잡한 분석 수행

이러한 기술은 특히 복잡한 로직이나 데이터 구조를 다룰 때 깔끔하고 유지 관리하기 쉬우며 강력한 SQL 쿼리를 작성하는 데 필수적입니다.