icon

안동민 개발노트

2장 : 관계형 데이터 모델

릴레이션의 개념


엑셀 시트를 열면 행과 열로 이루어진 표가 보입니다. 데이터베이스의 테이블도 겉보기에는 비슷해 보이지만, 내부적으로는 완전히 다른 규칙 위에 서 있습니다. 관계형 데이터베이스에서 테이블은 사실 수학의 릴레이션(Relation)이라는 개념에서 출발했습니다. 이 수학적 기반을 이해하면 SQL을 단순한 문법 암기가 아니라, 왜 이렇게 동작하는가를 근본적으로 파악하는 시각을 얻게 됩니다.

왜 굳이 수학적 배경까지 알아야 할까요? 테이블의 특성을 모르면 실무에서 예상치 못한 문제를 만납니다. SELECT *의 컬럼 순서가 매번 다를 수 있는 거지?, 왜 중복 행이 자동으로 제거되지 않는 거지?, 왜 하나의 셀에 여러 값을 넣으면 안 되는 거지? — 이 모든 질문의 답이 릴레이션의 수학적 정의에 있습니다.


관계형 모델의 탄생

1970년, IBM의 연구원 에드거 F. 코드(Edgar F. Codd)A Relational Model of Data for Large Shared Data Banks라는 논문을 발표했습니다. 이 논문이 관계형 데이터베이스의 시작입니다. 코드가 제안한 핵심 아이디어는 간단합니다. 데이터를 수학적 릴레이션(관계)으로 표현하자.

이전의 데이터베이스(계층형, 네트워크형)는 데이터 간의 물리적 연결(포인터, 링크)에 의존했습니다. 프로그래머가 데이터를 찾으려면 이 레코드에서 저 포인터를 따라가서, 다시 이 링크를 거쳐서... 하는 식으로 내비게이션을 직접 해야 했습니다. 데이터의 물리적 저장 구조가 바뀌면 프로그램 전체를 다시 작성해야 했습니다.

코드는 이런 물리적 구조에 대한 의존을 없애고, 데이터를 논리적인 표(릴레이션)로만 바라보자고 제안했습니다. 데이터가 디스크에 어떻게 저장되든, 사용자는 릴레이션(테이블)만 보면 된다는 것입니다. 이것이 데이터 독립성의 시작이며, 관계형 데이터베이스가 수십 년간 지배적인 모델이 된 근본적인 이유입니다.


릴레이션이란 무엇인가

수학에서 릴레이션은 집합의 카르테시안 곱(Cartesian Product)의 부분집합입니다. 이 말이 어렵게 느껴질 수 있으니, 단계적으로 풀어보겠습니다.

도메인 D1D_1, D2D_2, ..., DnD_n이 있을 때, 이들의 카르테시안 곱 D1×D2×...×DnD_1 \times D_2 \times ... \times D_n은 각 도메인에서 하나씩 원소를 뽑아 만들 수 있는 모든 조합의 집합입니다. 릴레이션은 이 카르테시안 곱의 부분집합입니다. 즉, 가능한 모든 조합 중에서 의미 있는 조합만 모아놓은 것이 릴레이션입니다.

구체적으로 예를 들어보겠습니다.

도메인과 릴레이션의 관계
도메인 정의
  D₁(학번) = {2024001, 2024002, 2024003, ...}
  D₂(이름) = {"김철수", "이영희", "박민수", ...}
  D₃(학과) = {"컴퓨터", "경영학", "전자공학", ...}
  D₄(학년) = {1, 2, 3, 4}

카르테시안 곱 D₁ × D₂ × D₃ × D₄
  (2024001, "김철수", "컴퓨터", 1)    ← 의미 있음 ✓
  (2024001, "김철수", "컴퓨터", 2)    ← 한 학생이 1학년이면서 2학년? ✗
  (2024001, "이영희", "경영학", 3)    ← 학번과 이름 불일치 ✗
  ...수만 가지 조합

릴레이션 = 이 중 실제로 의미 있는 조합만 선택
  {(2024001, "김철수", "컴퓨터", 1),
   (2024002, "이영희", "경영학", 2),
   (2024003, "박민수", "컴퓨터", 1)}

수학적으로 릴레이션은 집합이므로, 집합의 성질을 그대로 이어받습니다. 집합에는 중복 원소가 없고, 원소의 순서가 없습니다. 이것이 바로 릴레이션의 특성으로 이어집니다.


릴레이션의 구성 요소

데이터베이스에서 릴레이션은 우리가 흔히 말하는 테이블과 동일합니다. 하지만 관계형 모델의 용어와 일상적인 용어는 구분해서 알아야 합니다.

릴레이션 구성 요소
릴레이션 스키마: students(학번, 이름, 학과, 학년)
릴레이션 인스턴스(현재 저장된 데이터)

┌─────────┬───────┬─────────┬──────┐
│  학번   │ 이름  │  학과   │ 학년 │  ← 속성(Attribute) = 컬럼
├─────────┼───────┼─────────┼──────┤
│ 2024001 │ 김철수│ 컴퓨터  │  1   │  ← 튜플(Tuple) = 행
│ 2024002 │ 이영희│ 경영학  │  2   │
│ 2024003 │ 박민수│ 컴퓨터  │  1   │
└─────────┴───────┴─────────┴──────┘

    도메인(Domain): 학번은 정수, 이름은 문자열

용어 대응

관계형 모델의 공식 용어, 데이터베이스의 실무 용어, 일상적인 표현은 같은 것을 가리키지만 이름이 다릅니다.

관계형 모델 용어실무 용어일상 표현설명
릴레이션(Relation)테이블(Table)데이터의 2차원 구조
튜플(Tuple)행(Row)레코드하나의 데이터 항목
속성(Attribute)열(Column)컬럼, 필드데이터의 특성
도메인(Domain)데이터 타입값의 범위속성이 가질 수 있는 값의 집합

교재나 논문에서는 릴레이션/튜플/속성이라는 용어를 쓰고, SQL에서는 테이블/행/열이라는 용어를 씁니다. 두 세계의 용어를 자유롭게 오가면서 소통할 수 있어야 합니다.


속성(Attribute)과 도메인(Domain)

속성의 의미

속성(Attribute)은 릴레이션의 열(column)로, 저장하려는 데이터의 특성을 나타냅니다. students 릴레이션에서 학번, 이름, 학과, 학년이 각각 하나의 속성입니다. 속성의 이름은 하나의 릴레이션 내에서 유일해야 합니다. 학번이라는 이름을 가진 컬럼이 두 개 있을 수는 없습니다.

속성은 일종의 질문이라고 생각할 수 있습니다. 학번이라는 속성은 이 학생의 학번은 무엇인가?라는 질문이고, 각 튜플의 해당 속성 값이 그 질문에 대한 답입니다.

도메인의 의미

도메인(Domain)은 속성이 가질 수 있는 값의 범위, 즉 허용 가능한 값의 집합입니다. 프로그래밍에서의 "데이터 타입"과 비슷하지만 더 넓은 개념입니다.

도메인 예시
속성: 학년
  도메인: {1, 2, 3, 4}  ← 정수 중에서도 1~4만 허용

속성: 이메일
  도메인: xxx@xxx.xxx 형태의 문자열  ← 단순 문자열이 아님

속성: 성별
  도메인: {'M', 'F'}  ← 두 값만 허용

속성: 학점
  도메인: 0.0 ~ 4.5 사이의 실수  ← 범위 제한

도메인은 단순한 데이터 타입(INTEGER, VARCHAR)을 넘어서, 의미적인 제한까지 포함합니다. 학년은 정수(INTEGER)이지만, 모든 정수가 유효한 학년은 아닙니다. 실제 DBMS에서는 CHECK 제약 조건을 사용하여 도메인을 구현합니다.

SQL에서의 도메인 구현
-- 도메인을 CHECK 제약으로 구현
CREATE TABLE students (
    student_id  NUMBER       NOT NULL,
    name        VARCHAR2(50) NOT NULL,
    department  VARCHAR2(30) NOT NULL,
    grade       NUMBER       CHECK (grade BETWEEN 1 AND 4),
    email       VARCHAR2(100),
    gender      CHAR(1)      CHECK (gender IN ('M', 'F'))
);

같은 도메인에 속하는 속성들은 비교 연산이 가능합니다. 예를 들어, 주문일배송일은 둘 다 날짜 도메인이므로 주문일 < 배송일 같은 비교가 의미 있습니다. 하지만 학번학년은 둘 다 정수이지만 도메인이 다르므로, 학번 = 학년 같은 비교는 의미가 없습니다. DBMS가 문법적으로 허용하더라도 논리적으로 올바르지 않습니다.

이처럼 도메인은 데이터 타입 + 의미적 제약이라고 이해하면 됩니다. 실무에서는 ENUM 타입이나 CHECK 제약, 또는 애플리케이션 레벨의 검증으로 도메인을 구현합니다.


튜플(Tuple)

튜플(Tuple)은 릴레이션의 행(row)으로, 하나의 개체(entity)에 대한 데이터를 나타냅니다. 위 예에서 (2024001, "김철수", "컴퓨터", 1)이 하나의 튜플입니다.

튜플은 각 속성에 대한 값의 순서쌍입니다. n개의 속성을 가진 릴레이션의 튜플은 n개의 값을 가지며, 이를 n-튜플이라 합니다. students 릴레이션은 4개의 속성을 가지므로 각 튜플은 4-튜플입니다.

실무에서 튜플은 보통 레코드(Record)행(Row)이라 부릅니다. SQL에서 INSERT INTO 구문으로 삽입하는 것이 바로 하나의 튜플입니다.

튜플 삽입
-- 하나의 튜플(행)을 삽입
INSERT INTO students (student_id, name, department, grade)
VALUES (2024004, '최수진', '전자공학', 2);

-- 이 INSERT 문이 실행되면 릴레이션 인스턴스에 튜플이 하나 추가됨

차수(Degree)와 카디널리티(Cardinality)

릴레이션의 크기를 표현하는 두 가지 측정치가 있습니다.

차수(Degree)는 릴레이션의 속성(컬럼)의 수입니다. students(학번, 이름, 학과, 학년) 릴레이션의 차수는 4입니다. 차수는 릴레이션의 스키마에 의해 결정되므로 자주 변하지 않습니다. 새로운 컬럼을 추가하거나(ALTER TABLE ADD) 기존 컬럼을 삭제할 때(ALTER TABLE DROP)만 변합니다.

카디널리티(Cardinality)는 릴레이션의 튜플(행)의 수입니다. 데이터가 삽입·삭제됨에 따라 수시로 변합니다. 학생 3명이 등록된 상태라면 카디널리티는 3이고, 한 명이 추가되면 4가 됩니다.

차수와 카디널리티
students 릴레이션
┌─────────┬───────┬─────────┬──────┐
│  학번   │ 이름  │  학과   │ 학년 │   차수(Degree) = 4 (속성의 수)
├─────────┼───────┼─────────┼──────┤
│ 2024001 │ 김철수│ 컴퓨터  │  1   │
│ 2024002 │ 이영희│ 경영학  │  2   │   카디널리티(Cardinality) = 3
│ 2024003 │ 박민수│ 컴퓨터  │  1   │   (튜플의 수)
└─────────┴───────┴─────────┴──────┘
측정치의미변경 빈도SQL과의 관계
차수(Degree)속성(컬럼)의 수매우 드묾 (스키마 변경 시)ALTER TABLE ADD/DROP
카디널리티(Cardinality)튜플(행)의 수매우 잦음 (데이터 변경 시)INSERT/DELETE

카디널리티라는 용어는 데이터베이스에서 여러 맥락에서 사용됩니다. 릴레이션의 카디널리티(행의 수)와 속성의 카디널리티(고유 값의 수)는 다른 의미입니다. 인덱스를 다룰 때 카디널리티가 높다라고 하면 해당 컬럼의 고유 값이 많다는 뜻이며, 이는 인덱스 설계에서 중요한 개념입니다. 자세한 내용은 인덱스 장에서 다룹니다.


릴레이션의 특성

릴레이션은 일반적인 표(스프레드시트)와 겉모습은 비슷하지만, 수학적 정의에 따른 엄격한 특성이 있습니다. 이 특성들을 이해하면 SQL의 동작 방식을 자연스럽게 납득할 수 있습니다.

특성 1: 튜플의 유일성

릴레이션에서 동일한 튜플은 존재할 수 없습니다. 수학적으로 릴레이션은 집합(Set)이고, 집합에는 중복 원소가 없기 때문입니다. 이것이 기본키(Primary Key)가 존재하는 근본적인 이유입니다. 릴레이션에서 각 튜플을 유일하게 식별할 방법이 반드시 있어야 합니다.

실무에서 주의할 점은, SQL의 테이블은 수학적인 릴레이션과 달리 중복 행을 허용한다는 것입니다. 기본키나 UNIQUE 제약이 없는 테이블에는 완전히 동일한 행이 들어갈 수 있습니다. 이것은 SQL이 순수한 관계형 모델에서 벗어난 부분입니다. 따라서 실무에서는 반드시 기본키를 지정하여 튜플의 유일성을 보장해야 합니다.

중복 행 문제
-- 기본키 없는 테이블 (권장하지 않음)
CREATE TABLE log_bad (
    event_date DATE,
    message    VARCHAR2(200)
);

-- 같은 데이터를 두 번 넣으면 중복 행 발생
INSERT INTO log_bad VALUES (DATE '2024-01-15', '서버 시작');
INSERT INTO log_bad VALUES (DATE '2024-01-15', '서버 시작');

-- 둘 중 하나만 삭제하는 것이 매우 어려움!
-- → 기본키가 있었다면 이 문제가 발생하지 않음

특성 2: 튜플의 순서 무의미

릴레이션에서 튜플(행)의 순서는 의미가 없습니다. 집합의 원소에는 순서가 없기 때문입니다. {a, b, c}{c, a, b}는 같은 집합입니다. 마찬가지로 김철수가 첫 번째 행, 이영희가 두 번째 행이라는 것에 아무 의미가 없습니다.

이 특성 때문에 SELECT * FROM students를 실행할 때 행의 순서가 보장되지 않습니다. 어떤 때는 학번 순으로 나오고, 어떤 때는 삽입 순서로 나올 수 있습니다. DBMS가 내부적으로 가장 효율적인 순서로 반환하기 때문입니다.

순서 보장 문제
-- 이 쿼리의 결과 순서는 보장되지 않음!
SELECT * FROM students;

-- 특정 순서가 필요하면 반드시 ORDER BY를 명시해야 함
SELECT * FROM students ORDER BY student_id;

실무에서 이상하게 아까는 학번 순서대로 나왔는데 지금은 아니에요라는 상황이 바로 이 특성 때문입니다. ORDER BY 없이 순서를 기대하는 것은 릴레이션의 본질을 모르는 것입니다.

특성 3: 속성의 순서 무의미

속성(컬럼)의 순서도 의미가 없습니다. students(학번, 이름, 학과, 학년)students(이름, 학과, 학번, 학년)은 수학적으로 같은 릴레이션입니다. 속성은 이름으로 식별하지, 위치(첫 번째, 두 번째)로 식별하지 않습니다.

하지만 실무에서는 SELECT *를 사용할 때 컬럼이 특정 순서로 반환됩니다. 이 순서는 CREATE TABLE 때 정의한 순서를 따르는 것이 일반적이지만, SQL 표준에서 보장하는 것은 아닙니다. 따라서 프로그램에서 SELECT *의 결과를 컬럼 위치(인덱스)로 접근하는 것은 위험합니다. 반드시 컬럼 이름으로 접근해야 합니다.

안전한 접근 방식
-- 위험: 컬럼 위치에 의존
-- rs.getString(1)  ← 첫 번째 컬럼이 학번이라고 가정

-- 안전: 컬럼 이름으로 접근
-- rs.getString("student_id")  ← 컬럼 순서와 무관

-- 더 좋은 방법: SELECT * 대신 컬럼을 명시
SELECT student_id, name, department, grade
FROM students;

특성 4: 속성의 원자값 (Atomic Value)

릴레이션의 각 속성 값은 원자적(Atomic)이어야 합니다. 즉, 하나의 셀에는 하나의 값만 들어가야 합니다. 더 이상 분해할 수 없는 단일 값이어야 한다는 뜻입니다.

원자값 위반 사례
❌ 잘못된 설계 (원자값 위반)
┌──────┬──────────────┐
│ 이름 │   전화번호   │
├──────┼──────────────┤
│김철수│010-1234-5678,│ ← 하나의 셀에 여러 값!
│      │ 02-555-1234  │
└──────┴──────────────┘

✓ 올바른 설계 (원자값 준수)
방법 1 — 별도 행으로 분리
┌──────┬──────────────┬──────┐
│ 이름 │   전화번호   │ 유형 │
├──────┼──────────────┼──────┤
│김철수│ 010-1234-5678│휴대폰│
│김철수│ 02-555-1234  │ 자택 │
└──────┴──────────────┴──────┘

방법 2 — 별도 테이블로 분리
users 테이블
┌─────┬──────┐
│ ID  │ 이름 │
├─────┼──────┤
│  1  │김철수│
└─────┴──────┘

phone_numbers 테이블
┌─────┬──────────────┬──────┐
│ ID  │   전화번호   │ 유형 │
├─────┼──────────────┼──────┤
│  1  │ 010-1234-5678│휴대폰│
│  1  │ 02-555-1234  │ 자택 │
└─────┴──────────────┴──────┘
→ phone_numbers.ID가 users.ID를 참조

이 원자값 특성은 제1정규형(1NF)의 조건과 직결됩니다. 릴레이션이 되려면 모든 속성이 원자값이어야 하며, 이것이 곧 1NF를 만족하는 것입니다. 정규화 장에서 자세히 다루겠지만, 원자값 위반은 데이터 중복, 갱신 이상(anomaly) 등 심각한 문제를 유발합니다.

특성 5: 속성의 이름은 유일

하나의 릴레이션 내에서 동일한 이름의 속성이 있을 수 없습니다. students 테이블에 이름이라는 컬럼이 두 개 있으면, SQL에서 SELECT 이름 FROM students라고 썼을 때 어떤 컬럼을 말하는지 알 수 없습니다. 따라서 속성 이름은 반드시 유일해야 합니다.

다만, 서로 다른 릴레이션에서는 같은 이름의 속성이 있을 수 있습니다. students.nameprofessors.name처럼 릴레이션 이름으로 구분합니다.

특성 정리 표

특성수학적 근거의미SQL에서의 영향
튜플의 유일성집합에 중복 없음동일한 행 존재 불가PRIMARY KEY로 보장
튜플 순서 무의미집합에 순서 없음행의 순서 보장 안 됨ORDER BY 필수
속성 순서 무의미이름으로 식별컬럼 순서 보장 안 됨컬럼명으로 접근
속성의 원자값단일 값만 허용한 셀에 한 값1NF, CHECK 제약
속성 이름 유일식별 가능성같은 이름 컬럼 불가테이블 내 유일

릴레이션 스키마 vs 인스턴스

릴레이션은 구조(스키마)내용(인스턴스)을 명확히 구분합니다. 이 구분은 데이터베이스 설계와 운영의 핵심입니다.

릴레이션 스키마 (Schema)

릴레이션 스키마(Relation Schema)는 릴레이션의 구조적 정의입니다. 릴레이션의 이름, 속성의 이름, 각 속성의 도메인을 포함합니다. 형식적으로는 다음과 같이 표현합니다.

릴레이션 스키마 표기
R(A₁, A₂, ..., Aₙ)

예: students(학번, 이름, 학과, 학년)
    orders(주문번호, 고객ID, 주문일, 총금액)
    products(상품코드, 상품명, 가격, 재고)

스키마는 데이터베이스의 설계도에 해당합니다. 건물의 설계도가 자주 바뀌지 않듯이, 스키마도 한번 정의되면 쉽게 변하지 않습니다. SQL의 DDL(Data Definition Language)이 스키마를 다루는 언어입니다.

스키마 정의 = DDL
-- CREATE TABLE이 릴레이션 스키마를 정의하는 것
CREATE TABLE students (
    student_id  NUMBER       PRIMARY KEY,
    name        VARCHAR2(50) NOT NULL,
    department  VARCHAR2(30),
    grade       NUMBER       CHECK (grade BETWEEN 1 AND 4)
);

릴레이션 인스턴스 (Instance)

릴레이션 인스턴스(Relation Instance)는 특정 시점에 릴레이션에 저장된 튜플의 집합입니다. 데이터가 삽입, 수정, 삭제됨에 따라 수시로 변합니다. SQL의 DML(Data Manipulation Language)이 인스턴스를 다루는 언어입니다.

시점에 따라 변하는 인스턴스
[2024년 3월 2일 인스턴스]
┌─────────┬───────┬─────────┬──────┐
│  학번   │ 이름  │  학과   │ 학년 │
├─────────┼───────┼─────────┼──────┤
│ 2024001 │ 김철수│ 컴퓨터  │  1   │
│ 2024002 │ 이영희│ 경영학  │  2   │
└─────────┴───────┴─────────┴──────┘
카디널리티 = 2

[2024년 9월 1일 인스턴스 — 신입생 추가, 학년 변경]
┌─────────┬───────┬─────────┬──────┐
│  학번   │ 이름  │  학과   │ 학년 │
├─────────┼───────┼─────────┼──────┤
│ 2024001 │ 김철수│ 컴퓨터  │  2   │  ← 학년 변경
│ 2024002 │ 이영희│ 경영학  │  3   │  ← 학년 변경
│ 2024051 │ 최수진│ 전자공학│  1   │  ← 신규 튜플
│ 2024052 │ 한지민│ 컴퓨터  │  1   │  ← 신규 튜플
└─────────┴───────┴─────────┴──────┘
카디널리티 = 4

스키마와 인스턴스의 관계를 프로그래밍 용어로 비유하면, 스키마는 클래스(Class)이고 인스턴스는 객체(Object)입니다. 클래스는 어떤 속성을 가질지 정의하고, 객체는 실제 값을 가집니다.

비교릴레이션 스키마릴레이션 인스턴스
정의릴레이션의 구조 (이름, 속성, 도메인)특정 시점의 튜플 집합
변경 빈도거의 변하지 않음수시로 변함
SQLDDL (CREATE, ALTER, DROP)DML (SELECT, INSERT, UPDATE, DELETE)
프로그래밍 비유클래스 정의객체(인스턴스)
예시students(학번, 이름, 학과, 학년){(2024001, 김철수, 컴퓨터, 1), ...}

데이터베이스 스키마와 릴레이션 스키마의 차이

혼동하기 쉬운 개념을 정리합니다. 릴레이션 스키마는 하나의 테이블의 구조이고, 데이터베이스 스키마는 데이터베이스 전체의 구조(모든 테이블, 뷰, 제약 조건, 관계 등의 총체)입니다.

스키마의 계층
데이터베이스 스키마 (Database Schema)
├── 릴레이션 스키마: students(학번, 이름, 학과, 학년)
├── 릴레이션 스키마: courses(과목코드, 과목명, 학점, 담당교수)
├── 릴레이션 스키마: enrollments(학번, 과목코드, 성적)
├── 뷰: student_grades_view(...)
├── 제약 조건: enrollments.학번 → students.학번 (외래키)
└── 인덱스: idx_students_name ON students(이름)

릴레이션과 SQL의 차이점

이론적인 릴레이션과 실제 SQL의 테이블은 몇 가지 중요한 차이가 있습니다. 이 차이를 이해하면 SQL의 동작을 더 정확히 예측할 수 있습니다.

구분릴레이션 (이론)SQL 테이블 (실제)
중복 행허용 안 됨 (집합)허용됨 (멀티셋/Bag)
NULL개념 없음허용됨
행의 순서없음ORDER BY로 지정 가능
속성 순서없음CREATE TABLE 순서 유지

가장 큰 차이는 중복 행NULL입니다.

수학적 릴레이션은 집합이므로 중복이 없지만, SQL 테이블은 PRIMARY KEY를 지정하지 않으면 중복 행을 허용합니다. 이 때문에 SQL에서는 DISTINCT 키워드를 사용하여 중복을 제거해야 하는 상황이 생깁니다. 순수한 관계형 모델에서는 DISTINCT가 필요 없었을 것입니다.

NULL은 관계형 모델의 원래 정의에는 없는 개념입니다. NULL은 "값이 없음" 또는 "알 수 없음"을 나타내며, 3값 논리(True, False, Unknown)를 도입하여 SQL의 복잡성을 크게 높였습니다. NULL과 관련된 문제는 SQL 장에서 자세히 다룹니다.

릴레이션 이론 vs SQL 현실
-- 1. 중복 행 문제
-- 릴레이션에서는 불가능하지만, SQL에서는 가능
SELECT department FROM students;
-- 결과: '컴퓨터', '경영학', '컴퓨터'  ← 중복!

-- 집합으로 만들려면 DISTINCT 필요
SELECT DISTINCT department FROM students;
-- 결과: '컴퓨터', '경영학'

-- 2. NULL 문제
-- NULL은 "모르는 값"이므로 비교 자체가 Unknown
SELECT * FROM students WHERE department = NULL;    -- 결과 없음!
SELECT * FROM students WHERE department IS NULL;    -- 올바른 방법

릴레이션의 종류

데이터베이스에서 릴레이션은 저장 방식에 따라 여러 종류로 나뉩니다.

기본 릴레이션 (Base Relation)

기본 릴레이션CREATE TABLE로 생성되어 디스크에 물리적으로 저장되는 릴레이션입니다. 우리가 일반적으로 "테이블"이라 부르는 것이 기본 릴레이션입니다.

뷰 (View)

뷰(View)는 기본 릴레이션으로부터 유도되는 가상 릴레이션입니다. 물리적으로 저장되지 않고, 조회할 때마다 정의된 쿼리가 실행되어 결과를 만듭니다.

뷰의 정의와 사용
-- 뷰 정의: 컴퓨터학과 학생만 보는 가상 릴레이션
CREATE VIEW cs_students AS
SELECT student_id, name, grade
FROM students
WHERE department = '컴퓨터';

-- 뷰를 테이블처럼 조회 가능
SELECT * FROM cs_students;
-- 실제로는 위의 SELECT 문이 실행됨

뷰는 데이터의 보안(특정 컬럼만 공개), 편의성(복잡한 쿼리 간소화), 논리적 독립성(테이블 구조 변경 시 뷰로 기존 인터페이스 유지)에 활용됩니다.

임시 릴레이션 (Temporary Relation)

SQL 쿼리의 중간 결과도 릴레이션입니다. SELECT 문의 결과는 새로운 릴레이션을 만들어냅니다. 이것이 SQL에서 서브쿼리를 사용할 수 있는 이유입니다. 쿼리의 결과가 릴레이션이므로, 그 결과에 다시 쿼리를 적용할 수 있습니다. 이 성질을 릴레이션의 폐쇄성(Closure Property)이라 합니다.

쿼리 결과도 릴레이션
-- 외부 쿼리의 FROM 절에 서브쿼리(결과 릴레이션) 사용
SELECT department, avg_grade
FROM (
    SELECT department, AVG(grade) AS avg_grade
    FROM students
    GROUP BY department
) dept_summary            -- 이 서브쿼리 결과도 릴레이션
WHERE avg_grade >= 2.0;

릴레이션과 엑셀의 차이

릴레이션의 특성을 엑셀 스프레드시트와 비교하면 차이가 더욱 명확해집니다.

항목엑셀 스프레드시트릴레이션(테이블)
셀에 여러 값가능 (서울, 부산)불가 (원자값)
중복 행자유롭게 허용기본키로 방지
행의 순서의미 있음 (행 번호)의미 없음
열의 순서의미 있음 (A, B, C열)의미 없음 (이름으로 식별)
빈 셀그냥 비어 있음NULL (특수한 의미)
데이터 타입자유 (한 열에 숫자·문자 혼재)엄격 (도메인 제한)
셀 병합가능불가능
수식셀 참조 수식 가능속성 값에 수식 불가

엑셀에서 자유롭게 할 수 있는 것들이 릴레이션에서는 대부분 제한됩니다. 이 제한이 바로 데이터의 무결성(Integrity)을 보장하는 장치입니다. 엑셀에서 실수로 같은 주문을 두 번 입력하면 아무도 모르지만, 기본키가 있는 테이블에서는 즉시 오류가 발생합니다.


NULL의 의미와 문제

릴레이션 이론에서는 모든 속성에 값이 있어야 하지만, 현실에서는 아직 모르는 값, 해당 없는 값이 필연적으로 존재합니다. 이를 표현하기 위해 도입된 것이 NULL입니다.

NULL은 값이 없음이 아니라 값을 알 수 없음(Unknown)입니다. 0이나 빈 문자열('')과는 완전히 다른 개념입니다.

NULL vs 0 vs ''
학생의 중간고사 성적
  - 80점     → 값이 있음 (정상)
  - 0점      → 값이 있음 (시험을 봤으나 0점)
  - NULL     → 값을 모름 (시험을 안 봤거나, 아직 채점 안 됨)
  - ''(빈문자)→ 값이 있으나 내용이 빈 것 (NULL과 다름)

NULL은 3값 논리(Three-Valued Logic)를 발생시키므로 주의가 필요합니다.

표현결과이유
NULL = NULLUnknown모르는 값끼리 같은지 알 수 없음
NULL <> 1Unknown모르는 값이 1이 아닌지 알 수 없음
NULL + 10NULL모르는 값에 10을 더해도 모름
NULL AND TRUEUnknown모르는 값이 참인지 알 수 없음

NULL 때문에 WHERE 조건에서 = NULL 대신 IS NULL을 써야 하고, 집계 함수에서 NULL 행이 무시되는 등 여러 복잡한 동작이 발생합니다. 이 내용은 SQL 장에서 깊이 다룹니다.


정리

이 절에서 다룬 릴레이션의 핵심 개념을 정리하겠습니다.

릴레이션은 관계형 데이터베이스의 수학적 기반입니다. 에드거 코드가 1970년에 제안한 관계형 모델에서 출발하여, 데이터를 논리적인 표(릴레이션)로 표현합니다. 릴레이션은 속성(컬럼)과 튜플(행)으로 구성되며, 각 속성은 도메인(가능한 값의 범위)을 가집니다.

릴레이션의 크기는 차수(속성의 수)와 카디널리티(튜플의 수)로 측정합니다. 차수는 스키마에 의해 결정되어 자주 변하지 않고, 카디널리티는 데이터 변경에 따라 수시로 변합니다.

릴레이션의 5가지 특성 — 튜플의 유일성, 튜플 순서 무의미, 속성 순서 무의미, 속성의 원자값, 속성 이름의 유일성 — 은 모두 수학적 집합론에서 유래하며, SQL의 동작 방식을 이해하는 핵심 열쇠입니다.

릴레이션 스키마(구조)와 릴레이션 인스턴스(데이터)를 구분하는 것은 데이터베이스 설계에서 필수적입니다. DDL이 스키마를 다루고, DML이 인스턴스를 다루며, 이 두 계층의 분리가 데이터 독립성의 기반입니다.

다음 절에서는 릴레이션에서 튜플을 유일하게 식별하는 키(Key)를 다루겠습니다.

목차