본문 바로가기

SQL

오라클 - 정규화부터 서브쿼리

1. 데이터베이스 정규화 (Normalization)

DB 설계 단계에서 가장 중요한 건 중복 제거와 이상현상 방지다.
정규화 과정을 통해 구조를 깔끔하게 만들 수 있다.

  • 1차 정규화 (1NF)
    모든 속성은 원자값만 가져야 한다.
    예) 전화번호를 여러 개 넣지 말고, 전화번호 테이블을 분리한다.
  • 2차 정규화 (2NF)
    1NF 만족 + 기본키의 부분집합에만 종속된 속성 제거.
    예) (학생ID, 과목ID) → 성적, 여기서 "학생 주소"는 학생ID만으로 결정되므로 분리.
  • 3차 정규화 (3NF)
    2NF 만족 + 기본키가 아닌 속성이 다른 속성에 종속되면 제거.
    예) 학생 테이블에서 학과ID → 학과명 관계가 있다면 학과 테이블로 분리.

2. 참조 무결성과 외래키 제약

  • 참조 무결성 (Referential Integrity)
    자식 테이블의 FK는 반드시 부모 테이블의 PK를 참조해야 한다.
CREATE TABLE tEmployee (
    name CHAR(10) PRIMARY KEY
);
CREATE TABLE tProject (
    projectID INT PRIMARY KEY,
    employee CHAR(10) NOT NULL,
    project VARCHAR(30) NOT NULL,
    CONSTRAINT FK_emp FOREIGN KEY(employee) REFERENCES tEmployee(name)
);

➡ tProject.employee 값은 반드시 tEmployee.name 중 하나여야 한다.

  • 외래키 선언 방식
    • 컬럼 레벨 지정
    • 테이블 레벨 지정 (실무 권장 – 유지보수 용이)
  • 연계 참조 무결성 (Referential Actions)
    부모 삭제 시 자식 처리 옵션:
    • NO ACTION (기본값, 오류 발생)
    • CASCADE (자식도 같이 삭제)
    • SET NULL (자식 FK NULL 처리)
    • 오라클은 ON UPDATE CASCADE 지원 x (트리거로 구현)

3. VARCHAR vs VARCHAR2

  • VARCHAR : ANSI 표준, 내부적으로 VARCHAR2로 변환됨
  • VARCHAR2 : 오라클 고유, 가변 길이 문자열
  • 오라클에서는 VARCHAR2 사용 권장

4. ENUM 타입 대체 방법 (Oracle)

MySQL의 ENUM은 오라클에 없음 → 아래 두 가지로 대체:

  1. CHECK 제약조건
status NUMBER CHECK (status IN (1,2,3,4))
  1. 코드 테이블 방식 (실무 권장)
    별도 테이블을 만들어 FK로 연결
    ➡ 상태값 확장/관리 용이

5. SQL 쿼리 동작 순서

많이 헷갈리는 부분인데, SQL 실행 순서는 우리가 작성한 순서와 다르다.

실행 순서 (논리적 처리 순서)

  1. FROM / JOIN
  2. WHERE
  3. GROUP BY
  4. HAVING
  5. SELECT
  6. ORDER BY

➡ 즉, SELECT가 먼저 오는 것 같지만, 실제로는 FROM → WHERE → GROUP BY → HAVING → SELECT → ORDER BY 순서대로 실행된다.


6. 서브쿼리 (Subquery)

SQL 안에 또 다른 SQL을 넣는 방식.
종류는 크게 단일행 / 다중행 / 다중열 / 연관 서브쿼리 / 인라인뷰로 나뉜다.

6-1) 단일행 서브쿼리

SELECT name
FROM tCity
WHERE popu = (SELECT MAX(popu) FROM tCity);

6-2) 다중행 서브쿼리 – IN

SELECT item
FROM tItem
WHERE item IN (SELECT item FROM tOrder WHERE member='향단');

6-3) ANY / ALL

-- ANY : 조건을 하나라도 만족하면 참
salary > ANY (SELECT salary FROM tStaff WHERE depart='영업부')
-- ALL : 모든 조건을 만족해야 참
salary > ALL (SELECT salary FROM tStaff WHERE depart='영업부')
  • > ANY → 최소값보다 크면 OK
  • > ALL → 최대값보다 커야 OK

6-4) EXISTS

SELECT *
FROM tMember m
WHERE EXISTS (
  SELECT 1
  FROM tOrder o
  WHERE o.member = m.member
);

➡ 주문이 존재하는 회원만 조회.
➡ EXISTS는 참/거짓만 반환하므로 성능이 좋다.

6-5) 인라인뷰

SELECT *
FROM (SELECT * FROM tCity WHERE metro = 'y') A;

➡ 서브쿼리를 FROM 절에서 사용 → 임시 테이블처럼 활용.


7. SQL 튜닝과 서브쿼리 최적화

  • EXISTS vs IN: 큰 테이블일 때는 EXISTS가 더 빠른 경우 많음
  • ANY, ALL: 잘못 쓰면 불필요한 Full Scan 발생
  • 인라인뷰: 가공된 데이터셋을 활용할 때 성능 최적화 가능

  • 정규화: 중복 제거, 이상현상 방지
  • 참조 무결성: FK는 반드시 유효한 PK 참조
  • VARCHAR2: 오라클 문자열 컬럼은 무조건 VARCHAR2 사용
  • ENUM: CHECK 제약조건 or 코드 테이블로 대체
  • 쿼리 동작 순서: FROM → WHERE → GROUP BY → HAVING → SELECT → ORDER BY
  • 서브쿼리: 단일행, 다중행, ANY/ALL, EXISTS, 인라인뷰
  • 튜닝 포인트: EXISTS 활용, 불필요한 서브쿼리 최소화

 

'SQL' 카테고리의 다른 글

SQL 조인 정리 (INNER, OUTER, 다중조인, 인라인 뷰 조인)  (0) 2025.06.12
LINQPad 로 LINQ 문 , SQL 문 연습하기  (0) 2025.06.09
JOIN 종류  (0) 2025.06.09