Keyword

SQL(Structured Query Language)는 데이터베이스를 관리하고 조작하기 위한 표준 언어로, 다양한 키워드를 통해 데이터 정의, 조작, 제어, 트랜잭션 관리 등을 수행한다.

데이터 조회 (Query) 키워드

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
-- SELECT: 데이터를 조회하는 기본 키워드
-- 지정된 컬럼의 데이터를 결과셋으로 반환
SELECT employee_id, first_name, salary
FROM employees;

-- FROM: 데이터를 가져올 테이블을 지정
-- 여러 테이블을 콤마로 구분하거나 JOIN을 사용할 수 있음
SELECT * 
FROM employees, departments;


-- DISTINCT: 결과에서 중복된 행을 제거하는 데 사용
-- 기본 DISTINCT 사용
-- 부서별 unique한 직무 목록 조회
SELECT DISTINCT job_id
FROM employees;

-- 여러 컬럼에 DISTINCT 적용
-- 부서와 직무의 unique한 조합 조회
SELECT DISTINCT department_id, job_id
FROM employees;

-- COUNT와 함께 사용
-- 회사에 존재하는 직무 개수 조회
SELECT COUNT(DISTINCT job_id) as unique_jobs
FROM employees;

-- GROUP BY와 함께 사용
SELECT department_id, 
       COUNT(DISTINCT job_id) as job_types
FROM employees
GROUP BY department_id;

결과 제한

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
-- LIMIT - 반환되는 결과의 최대 행 수를 제한합니다.
SELECT * FROM employees LIMIT 10  -- 상위 10개 행만 반환

-- OFFSET - 결과의 시작 위치를 지정합니다. LIMIT와 함께 자주 사용됩니다.
SELECT * FROM employees LIMIT 10 OFFSET 20  -- 21번째부터 30번째 행을 반환

-- FETCH - SQL 표준의 LIMIT와 유사한 기능을 합니다.
SELECT * FROM employees FETCH FIRST 10 ROWS ONLY

-- 페이지당 10개 항목, 3번째 페이지 조회
SELECT *
FROM products
ORDER BY name
LIMIT 10 OFFSET 20;  -- (페이지 번호 - 1) * 페이지 크기 = OFFSET

조건 연산자 키워드

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
-- WHERE: 조건절을 지정하여 특정 조건을 만족하는 데이터만 조회
-- AND, OR을 사용하여 여러 조건 조합 가능
SELECT * 
FROM employees 
WHERE salary > 50000 AND department_id = 10;

-- IN: 값 목록 중 포함 여부
-- BETWEEN: 범위 조건
-- LIKE: 패턴 매칭
-- IS NULL: NULL 값 확인
SELECT * FROM employees
WHERE department_id IN (10, 20, 30)
  AND salary BETWEEN 40000 AND 60000
  AND first_name LIKE '김%'
  AND manager_id IS NOT NULL;

-- CASE - 조건에 따라 다른 값을 반환합니다.
-- WHEN - CASE 문에서 조건을 지정합니다.
-- THEN - 조건이 참일 때 반환할 값을 지정합니다.
-- ELSE - 모든 조건이 거짓일 때 반환할 값을 지정합니다.
SELECT name,
       CASE 
           WHEN age < 20 THEN 'Young'
           WHEN age < 60 THEN 'Adult'
           ELSE 'Senior'
       END as age_group
FROM users;

정렬과 그룹화 키워드

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
-- GROUP BY: 지정된 컬럼을 기준으로 데이터를 그룹화
-- 주로 집계 함수와 함께 사용
SELECT department_id, AVG(salary)
FROM employees
GROUP BY department_id;

-- ORDER BY: 결과를 정렬
-- ASC(오름차순), DESC(내림차순) 지정 가능
SELECT * 
FROM employees
ORDER BY salary DESC, first_name ASC;

-- HAVING: GROUP BY로 그룹화된 데이터에 대한 조건 지정
-- WHERE는 개별 행에 대한 조건, HAVING은 그룹에 대한 조건
SELECT department_id, AVG(salary)
FROM employees
GROUP BY department_id
HAVING AVG(salary) > 50000;

조인(Join) 관련 키워드

JOIN은 두 개 이상의 테이블을 연결하여 데이터를 검색하는 방법이다. JOIN을 사용하면 여러 테이블의 데이터를 하나의 결과 집합으로 결합할 수 있다.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
-- JOIN: 여러 테이블을 연결
	-- INNER JOIN: 두 테이블에서 일치하는 데이터만 가져옵니다.
	-- LEFT JOIN: 왼쪽 테이블의 모든 데이터와 오른쪽 테이블의 일치하는 데이터를 가져옵니다.
	-- RIGHT JOIN: 오른쪽 테이블의 모든 데이터와 왼쪽 테이블의 일치하는 데이터를 가져옵니다.
	-- FULL JOIN: 양쪽 테이블의 모든 데이터를 가져옵니다.
-- ON: 조인 조건 지정
SELECT e.first_name, d.department_name
FROM employees e
JOIN departments d ON e.department_id = d.department_id;

SELECT c.customer_name, o.order_date
FROM customers c
LEFT JOIN orders o                         -- 주문이 없는 고객도 포함
	ON c.customer_id = o.customer_id
WHERE o.amount > 1000                      -- 고액 주문만 필터링
ORDER BY o.order_date DESC;                -- 최근 주문순 정렬

주요 종류

각 JOIN 유형은 데이터를 결합하는 방식이 다르므로, 상황에 따라 적절한 JOIN을 선택하여 사용해야 한다.
INNER JOIN은 가장 일반적으로 사용되며, LEFT JOIN과 RIGHT JOIN은 누락된 데이터를 포함해야 할 때 유용하다.
CROSS JOIN은 모든 조합을 생성하므로 주의해서 사용해야 하며, SELF JOIN은 계층 구조나 순위를 다룰 때 유용하다.

SQL Joins
https://www.sqlshack.com/internals-of-physical-join-operators-nested-loops-join-hash-match-join-merge-join-in-sql-server/

  1. INNER JOIN

    • 두 테이블에서 조건을 만족하는 행만 결과에 포함한다.
    • 가장 일반적으로 사용되는 JOIN 유형.
    • INNER 키워드는 생략 가능하다.
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    
    -- 직원과 부서 정보를 매칭하여 조회
    -- 부서가 할당된 직원만 조회됨
    SELECT 
        e.employee_id,
        e.first_name,
        d.department_name
    FROM employees e
    INNER JOIN departments d 
        ON e.department_id = d.department_id;
    
    -- 다중 테이블 INNER JOIN
    -- 직원, 부서, 위치 정보를 모두 매칭
    SELECT 
        e.first_name,
        d.department_name,
        l.city
    FROM employees e
    INNER JOIN departments d 
        ON e.department_id = d.department_id
    INNER JOIN locations l 
        ON d.location_id = l.location_id;
    
  2. LEFT JOIN (LEFT OUTER JOIN)

    • 왼쪽 테이블의 모든 행을 포함하고, 오른쪽 테이블에서 조건을 만족하는 행을 결합한다.
    • 조건을 만족하는 행이 오른쪽 테이블에 없으면 NULL 값으로 채워진다.
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    
    -- 모든 직원 정보와 해당되는 부서 정보 조회
    -- 부서가 없는 직원도 포함됨
    SELECT 
        e.employee_id,
        e.first_name,
        d.department_name
    FROM employees e
    LEFT JOIN departments d 
        ON e.department_id = d.department_id;
    
    -- 부서가 없는 직원만 조회
    SELECT 
        e.employee_id,
        e.first_name
    FROM employees e
    LEFT JOIN departments d 
        ON e.department_id = d.department_id
    WHERE d.department_id IS NULL;
    
  3. RIGHT JOIN (RIGHT OUTER JOIN)

    • 오른쪽 테이블의 모든 행을 포함하고, 왼쪽 테이블에서 조건을 만족하는 행을 결합한다.
    • 조건을 만족하는 행이 왼쪽 테이블에 없으면 NULL 값으로 채워진다.
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    
    -- 모든 부서 정보와 해당되는 직원 정보 조회
    -- 직원이 없는 부서도 포함됨
    SELECT 
        d.department_name,
        e.first_name
    FROM employees e
    RIGHT JOIN departments d 
        ON e.department_id = d.department_id;
    
    -- 직원이 없는 부서만 조회
    SELECT 
        d.department_name
    FROM employees e
    RIGHT JOIN departments d 
        ON e.department_id = d.department_id
    WHERE e.employee_id IS NULL;
    
  4. FULL OUTER JOIN

    • FULL OUTER JOIN은 양쪽 테이블의 모든 레코드를 반환한다.
    • MySQL에서는 직접 지원하지 않지만, LEFT JOIN과 RIGHT JOIN을 UNION하여 구현할 수 있다.
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    
    -- 모든 직원과 모든 부서 정보를 조회
    -- 매칭되지 않는 레코드도 모두 포함
    SELECT 
        e.first_name,
        d.department_name
    FROM employees e
    FULL OUTER JOIN departments d 
        ON e.department_id = d.department_id;
    
    -- 매칭되지 않는 레코드만 조회
    SELECT 
        e.first_name,
        d.department_name
    FROM employees e
    FULL OUTER JOIN departments d 
        ON e.department_id = d.department_id
    WHERE e.employee_id IS NULL 
       OR d.department_id IS NULL;
    
  5. CROSS JOIN

    • 두 테이블의 모든 가능한 조합을 생성한다.
    • 카티션 곱(Cartesian product)이라고도 한다.
    • 결과는 두 테이블 행 수의 곱과 같다.
    1
    2
    3
    4
    5
    6
    7
    
    -- 모든 직원과 모든 부서의 조합 생성
    -- 카테시안 곱(Cartesian Product) 생성
    SELECT 
        e.first_name,
        d.department_name
    FROM employees e
    CROSS JOIN departments d;
    
  6. SELF JOIN

    • 하나의 테이블을 자기 자신과 JOIN한다.
    • 같은 테이블을 두 번 참조하여 사용한다.
    • 주로 계층 구조나 관계를 표현할 때 사용된다.
    1
    2
    3
    4
    5
    6
    7
    
    -- 직원과 그들의 관리자 정보 조회
    SELECT 
        e1.first_name AS employee_name,
        e2.first_name AS manager_name
    FROM employees e1
    LEFT JOIN employees e2 
        ON e1.manager_id = e2.employee_id;
    

주의사항 및 최적화

  1. 인덱스 활용: 조인 조건에 사용되는 컬럼에 인덱스 생성

  2. 조인 조건 최적화: 더 작은 결과셋을 먼저 필터링

    1
    2
    3
    4
    5
    6
    
    SELECT e.first_name, d.department_name
    FROM employees e
    INNER JOIN departments d 
        ON e.department_id = d.department_id
    WHERE e.salary > 50000  -- 먼저 필터링
      AND d.location_id = 1700;
    
  3. 다중 테이블 조인 순서: 가장 제한적인 조건을 먼저 적용

    1
    2
    3
    4
    5
    6
    7
    8
    
    SELECT e.first_name, d.department_name, l.city
    FROM employees e
    INNER JOIN departments d 
        ON e.department_id = d.department_id
    INNER JOIN locations l 
        ON d.location_id = l.location_id
    WHERE e.salary > 50000
    ORDER BY e.first_name;
    

Null 관련

1
2
3
4
5
6
7
8
9
-- IS NULL - NULL 값을 확인합니다.
: SELECT * from users WHERE phone_number IS NULL

-- IS NOT NULL - NULL이 아닌 값을 확인합니다.
: SELECT * from users WHERE email IS NOT NULL

-- IFNULL/COALESCE - NULL 값을 다른 값으로 대체합니다.
: SELECT IFNULL(phone, 'No Phone') as contact
    SELECT COALESCE(phone, email, 'No Contact') as contact

집합 연산

1
2
3
4
5
6
7
8
9
-- UNION - 두 쿼리 결과를 합치고 중복을 제거합니다.
-- UNION ALL - 두 쿼리 결과를 중복 제거 없이 합칩니다.
-- INTERSECT - 두 쿼리 결과의 교집합을 반환합니다.
-- EXCEPT/MINUS - 첫 번째 쿼리 결과에서 두 번째 쿼리 결과를 뺀 차집합을 반환합니다.

예시:
SELECT name FROM employees
UNION
SELECT name FROM contractors;

집계 함수 관련 키워드

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
-- COUNT - 행의 개수를 세는 함수입니다.
-- 예: COUNT(*) 또는 COUNT(column_name)

-- SUM - 숫자 값들의 합계를 계산합니다.
-- 예: SUM(salary)

-- AVG - 평균값을 계산합니다.
-- 예: AVG(price)

-- MAX - 최대값을 찾습니다.
-- 예: MAX(score)

-- MIN - 최소값을 찾습니다.
-- 예: MIN(age)
SELECT 
    COUNT(*) as 직원수,
    SUM(salary) as 총급여,
    AVG(salary) as 평균급여,
    MAX(salary) as 최대급여,
    MIN(salary) as 최소급여
FROM employees;

윈도우 함수 관련

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
-- OVER - 윈도우 함수를 정의할 때 사용합니다.
-- 전체 판매액 대비 각 거래의 비율 계산
SELECT 
    employee_name,
    sales_amount,
    sales_amount / SUM(sales_amount) OVER () * 100 as percentage_of_total
FROM sales;

-- 결과:
-- employee_name    sales_amount    percentage_of_total
-- 김영희           5000.00         12.3%
-- 이철수           4500.00         11.1%
-- 박지민           6000.00         14.8%
-- …

-- PARTITION BY - 데이터를 그룹으로 나눕니다.
-- 부서별 평균 판매액과 각 거래액의 차이 계산
SELECT 
    employee_name,
    department,
    sales_amount,
    AVG(sales_amount) OVER (PARTITION BY department) as dept_avg,
    sales_amount - AVG(sales_amount) OVER (PARTITION BY department) as diff_from_avg
FROM sales;

-- 결과:
-- employee_name    department    sales_amount    dept_avg    diff_from_avg
-- 김영희           영업1팀       5000.00         4950.00     50.00
-- 이철수           영업1팀       4500.00         4950.00    -450.00
-- 박지민           영업2팀       6000.00         5250.00     750.00
-- …

-- ROW_NUMBER - 각 행에 순차적인 번호를 부여합니다.
-- 부서별, 날짜별 판매액 순위
SELECT 
    sales_date,
    department,
    employee_name,
    sales_amount,
    ROW_NUMBER() OVER (
        PARTITION BY department, sales_date 
        ORDER BY sales_amount DESC
    ) as daily_rank
FROM sales;

-- 결과:
-- sales_date    department    employee_name    sales_amount    daily_rank
-- 2024-01-15    영업1팀       김영희           5000.00         1
-- 2024-01-15    영업1팀       이철수           4500.00         2
-- 2024-01-15    영업2팀       박지민           6000.00         1
-- …

-- RANK - 순위를 매깁니다(동점 시 같은 순위, 다음 순위는 건너뜀).
-- DENSE_RANK - 순위를 매깁니다(동점 시 같은 순위, 다음 순위는 연속).
-- 전체 판매액 기준 순위 비교
SELECT 
    employee_name,
    sales_amount,
    RANK() OVER (ORDER BY sales_amount DESC) as rank_num,
    DENSE_RANK() OVER (ORDER BY sales_amount DESC) as dense_rank_num,
    ROW_NUMBER() OVER (ORDER BY sales_amount DESC) as row_num
FROM sales;

-- 결과:
-- employee_name    sales_amount    rank_num    dense_rank_num    row_num
-- 박지민           6000.00         1           1                 1
-- 박지민           5800.00         2           2                 2
-- 김영희           5500.00         3           3                 3
-- 김영희           5000.00         4           4                 4
-- 이철수           4800.00         5           5                 5
-- …

서브쿼리

서브쿼리(Subquery)는 다른 SQL 쿼리 내부에 중첩된 쿼리를 의미한다.
서브쿼리를 사용하면 복잡한 쿼리를 더 작고 관리하기 쉬운 부분으로 나눌 수 있으며, 데이터를 더 효율적으로 검색하고 조작할 수 있다.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
-- EXISTS: 서브쿼리 결과의 존재 여부 확인
-- 주문이 있는 고객만 조회
SELECT customer_name
FROM customers c
WHERE EXISTS (
    SELECT 1 
    FROM orders o
    WHERE o.customer_id = c.customer_id
);

-- IN: 서브쿼리 결과 중 하나와 일치
-- 서울에 있는 부서의 직원들 조회
SELECT employee_id, first_name
FROM employees
WHERE department_id IN (
    SELECT department_id
    FROM departments
    WHERE location = 'Seoul'
);

-- ANY: 서브쿼리 결과 중 하나라도 조건 만족
-- 자신의 부서 평균 급여보다 많이 받는 직원 조회
SELECT first_name, salary
FROM employees e1
WHERE salary > ANY (
    SELECT AVG(salary)
    FROM employees e2
    WHERE e2.department_id = e1.department_id
);

-- ALL: 서브쿼리 결과 모두와 조건 만족
-- 모든 부서의 평균 급여보다 많이 받는 직원 조회
SELECT first_name, salary
FROM employees
WHERE salary > ALL (
    SELECT AVG(salary)
    FROM employees
    GROUP BY department_id
);

-- SOME: ANY와 동일한 의미
SELECT first_name, salary
FROM employees
WHERE salary > SOME (
    SELECT salary
    FROM employees
    WHERE department_id = 20
);

주요 특징:

  1. 괄호로 묶어 사용한다.
  2. 메인 쿼리와 독립적으로 실행될 수 있다.
  3. 메인 쿼리의 조건이나 결과에 따라 동적으로 실행될 수 있다.

장점:

  • 복잡한 쿼리를 더 읽기 쉽고 관리하기 쉽게 만든다.
  • 데이터를 단계별로 처리할 수 있다.
  • 동적인 조건을 쉽게 구현할 수 있다.

단점:

  • 과도한 사용은 성능 저하를 초래할 수 있다.
  • 복잡한 서브쿼리는 디버깅이 어려울 수 있다.
  • 일부 경우에는 JOIN으로 대체하여 더 나은 성능을 얻을 수 있다.

유형:

  1. 스칼라 서브쿼리: 단일 값을 반환한다.
  2. 행 서브쿼리: 단일 행을 반환한다.
  3. 열 서브쿼리: 단일 열을 반환한다.
  4. 테이블 서브쿼리: 전체 결과 집합을 반환한다.

사용 위치:

  1. SELECT 절
  2. FROM 절
  3. WHERE 절
  4. HAVING 절
  5. ORDER BY 절
  6. INSERT, UPDATE, DELETE 문

서브쿼리의 특별한 용법:

  1. 상관 서브쿼리 (Correlated Subquery)

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    
    -- 각 부서별 평균 급여보다 많이 받는 직원 조회
    SELECT e1.first_name, 
           e1.salary,
           e1.department_id
    FROM employees e1
    WHERE salary > (
        SELECT AVG(salary)
        FROM employees e2
        WHERE e2.department_id = e1.department_id
    );
    
  2. 인라인 뷰 (Inline View)

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    
    -- FROM 절에서 서브쿼리 사용
    SELECT e.first_name,
           d.avg_salary
    FROM employees e
    JOIN (
        SELECT department_id, 
               AVG(salary) as avg_salary
        FROM employees
        GROUP BY department_id
    ) d ON e.department_id = d.department_id
    WHERE e.salary > d.avg_salary;
    
  3. 스칼라 서브쿼리 (Scalar Subquery)

    1
    2
    3
    4
    5
    6
    7
    
    -- SELECT 절에서 서브쿼리 사용
    SELECT e.first_name,
           e.salary,
           (SELECT AVG(salary) 
            FROM employees 
            WHERE department_id = e.department_id) as dept_avg
    FROM employees e;
    

서브쿼리 사용 시 주의사항:

  1. 성능 최적화

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    
    -- 서브쿼리보다 JOIN이 더 효율적인 경우
    -- 비효율적인 방법:
    SELECT *
    FROM employees e
    WHERE department_id IN (
        SELECT department_id
        FROM departments
        WHERE location_id = 1700
    );
    
    -- 효율적인 방법:
    SELECT e.*
    FROM employees e
    JOIN departments d ON e.department_id = d.department_id
    WHERE d.location_id = 1700;
    
  2. NULL 값 처리

    1
    2
    3
    4
    5
    6
    7
    8
    
    -- NOT IN 사용 시 NULL 처리 주의
    SELECT *
    FROM employees
    WHERE department_id NOT IN (
        SELECT department_id
        FROM departments
        WHERE department_id IS NOT NULL  -- NULL 체크 필요
    );
    

예시

  1. WHERE 절에서의 서브쿼리:

    1
    2
    
    SELECT * FROM employees
    WHERE salary > (SELECT AVG(salary) FROM employees);
    
  2. SELECT 절에서의 서브쿼리:

    1
    2
    3
    
    SELECT name,
    	  (SELECT COUNT(*) FROM orders WHERE orders.customer_id = customers.id) AS order_count
    FROM customers;
    
  3. FROM 절에서의 서브쿼리:

    1
    2
    3
    4
    
    SELECT avg_salary.department, avg_salary.average
    FROM (SELECT department, AVG(salary) AS average
    	 FROM employees
    	 GROUP BY department) AS avg_salary;
    
  4. 상관 서브쿼리:

    1
    2
    3
    
    SELECT * FROM employees e
    WHERE salary > (SELECT AVG(salary) FROM employees
    			   WHERE department = e.department);
    

데이터 정의 키워드

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
-- CREATE: 데이터베이스 객체 생성
CREATE TABLE employees (
    employee_id INT PRIMARY KEY,
    first_name VARCHAR(50)
);

-- ALTER: 데이터베이스 객체 수정
ALTER TABLE employees
ADD COLUMN email VARCHAR(100);

-- DROP: 데이터베이스 객체 삭제
DROP TABLE employees;

-- TRUNCATE: 테이블 데이터 전체 삭제
TRUNCATE TABLE temp_data;

제약조건 키워드

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
-- PRIMARY KEY: 기본키 지정
-- FOREIGN KEY: 외래키 지정
-- UNIQUE: 고유값 제약조건
-- CHECK: 값의 범위나 조건 지정
-- DEFAULT: 기본값 지정
CREATE TABLE orders (
    order_id INT PRIMARY KEY,
    customer_id INT FOREIGN KEY REFERENCES customers(id),
    order_date DATE DEFAULT CURRENT_DATE,
    amount DECIMAL(10,2) CHECK (amount > 0)
);

데이터 조작 키워드

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
-- INSERT: 새로운 데이터 추가
INSERT INTO employees (first_name, last_name, salary)
VALUES ('길동', '홍', 50000);

-- UPDATE: 기존 데이터 수정
UPDATE employees
SET salary = salary * 1.1
WHERE department_id = 20;

-- DELETE: 데이터 삭제
DELETE FROM employees
WHERE employment_status = 'RESIGNED';

-- MERGE: 데이터 병합 (업서트)
MERGE INTO target_table t
USING source_table s
ON (t.id = s.id)
WHEN MATCHED THEN UPDATE
WHEN NOT MATCHED THEN INSERT;

인덱스 관련

1
2
3
4
5
6
7
-- CREATE INDEX - 인덱스를 생성합니다.
-- DROP INDEX - 인덱스를 삭제합니다.
-- EXPLAIN - 쿼리의 실행 계획을 확인합니다.

예시:
CREATE INDEX idx_email ON users(email);
EXPLAIN SELECT * FROM users WHERE email = 'test@example.com';

뷰 관련

1
2
3
4
5
6
7
8
9
-- CREATE VIEW - 가상 테이블(뷰)을 생성합니다.
-- ALTER VIEW - 기존 뷰를 수정합니다.
-- DROP VIEW - 뷰를 삭제합니다.
-- MATERIALIZED VIEW - 실제 데이터를 저장하는 뷰를 생성합니다.

예시:
CREATE VIEW active_employees AS
SELECT * FROM employees
WHERE status = 'active';

데이터 타입 변환

1
2
3
4
5
6
-- CAST - 데이터 타입을 변환합니다.
-- CONVERT - 데이터 타입이나 문자셋을 변환합니다.

예시:
SELECT CAST(price AS DECIMAL(10,2)) as formatted_price
FROM products;

데이터 정리 관련

1
2
3
4
5
6
7
8
9
-- TRIM - 문자열 앞뒤의 공백을 제거합니다.
-- LTRIM - 문자열 왼쪽의 공백을 제거합니다.
-- RTRIM - 문자열 오른쪽의 공백을 제거합니다.
-- REPLACE - 문자열 내의 특정 문자를 다른 문자로 대체합니다.

예시:
SELECT TRIM(' Hello World ') as cleaned_text,
       REPLACE(email, '@', '[at]') as masked_email
FROM users;

날짜 함수 관련

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
-- DATE_ADD/DATEADD - 날짜에 특정 기간을 더합니다.
-- DATE_SUB/DATESUB - 날짜에서 특정 기간을 뺍니다.
-- DATE_TRUNC - 날짜를 특정 단위로 잘라냅니다.
-- EXTRACT - 날짜에서 특정 부분(년, 월, 일 등)을 추출합니다.

예시:
SELECT 
    DATE_ADD(current_date, INTERVAL 1 MONTH) as next_month,
    EXTRACT(YEAR FROM hire_date) as hire_year
FROM employees;

트랜잭션 제어 키워드

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
-- START TRANSACTION: 트랜잭션 시작
START TRANSACTION;

-- COMMIT: 변경사항 확정
COMMIT;

-- ROLLBACK: 변경사항 취소
ROLLBACK;

-- SAVEPOINT: 트랜잭션 내 저장점 생성
SAVEPOINT save1;

권한 관리 키워드

1
2
3
4
5
6
7
8
-- GRANT: 권한 부여
GRANT SELECT, INSERT ON employees TO user_name;

-- REVOKE: 권한 회수
REVOKE UPDATE, DELETE ON employees FROM user_name;

-- DENY: 권한 명시적 거부 (MSSQL)
DENY SELECT ON sensitive_data TO user_name;

임시 테이블 관련

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
-- WITH (CTE) - Common Table Expression을 정의합니다.
-- TEMPORARY/TEMP - 임시 테이블을 생성합니다.

예시:
WITH monthly_sales AS (
    SELECT 
        DATE_TRUNC('month', sale_date) as month,
        SUM(amount) as total
    FROM sales
    GROUP BY DATE_TRUNC('month', sale_date)
)
SELECT * FROM monthly_sales;

참고 및 출처