Database
DATABASE #4. Relational Algebra 2
Frisbeen
2025. 4. 27. 23:49
관계대수(Relational Algebra) 개념 정리와 실전 예시
관계대수는 관계형 데이터베이스를 수학적으로 표현하는 언어로, 절차적인 언어입니다. 즉, 데이터를 어떤 방식으로 추출할지를 단계별로 명시합니다. SQL과는 달리 연산의 순서가 중요하고, 연산 결과도 항상 릴레이션(테이블)입니다.
1. 관계대수의 6가지 기본 연산 (복습)
- Select (σ): 수평 부분집합, 조건에 맞는 튜플만 선택
- Project (π): 수직 부분집합, 특정 속성만 선택 (중복 제거)
- Union (∪): 두 릴레이션의 합집합
- Set Difference (-): 차집합 (A에서 B를 뺀 것)
- Cartesian Product (×): 두 릴레이션의 곱집합
- Rename (ρ): 릴레이션이나 속성 이름 변경
※ 모든 연산 결과는 새로운 릴레이션 -> 매우 중요한 개념이다.
2. 추가 연산
▸ Set Intersection (∩)
- 두 릴레이션의 교집합
- 조건: 스키마 동일해야 함
▸ Join 연산
- 카타시안 곱 + 선택 조건의 조합을 단축한 연산
- Theta Join: 일반 조건 기반 조인 (중복 속성 유지)
- Equi Join: 조건이 등호인 Theta Join
- Natural Join: 공통 속성 기준으로 자동 조인. 중복 속성 제거됨
- Outer Join: 정보 소실 방지. NULL로 채움
- Left / Right / Full Outer Join 존재
▸ Division 연산 (r % s)
- "모든 조건을 만족하는 대상"을 구할 때 사용
- 결과 릴레이션의 속성 = r의 속성 - s의 속성
- r속성은 s의 속성의 모집합이어야한다.
▸ Aggregation 연산
- 집계 연산: AVG, SUM, COUNT, MIN, MAX 등
- 예: 학과별 교수의 평균 급여 구하기
3. 관계대수는 왜 괄호를 사용하는가?
관계대수는 절차적 언어이기 때문에, 연산의 순서가 중요합니다. 따라서 괄호를 통해 연산 우선순위를 명확하게 표현합니다.
실전 예시: Banking 데이터셋
🔎 문제 1: 페리릿지(Perryridge) 지점에서 대출을 받은 고객의 이름 찾기
π customer-name (
σ branch-name = "Perryridge" (loan)
⨝ loan.loan-number = borrower.loan-number
borrower
)
🔎 문제 2: 페리릿지에 대출은 있으나, 어떤 계좌도 갖고 있지 않은 고객
perry_Loan ← π customer-name (
σ branch-name = "Perryridge" (loan)
⨝ loan.loan-number = borrower.loan-number
borrower
)
Has_acc ← π customer-name (
perry_Loan
⨝ depositor.customer-name = borrower.customer-name
borrower
)
no_acc ← π customer-name (perry_Loan) − Has_acc
- 차집합은 두 릴레이션의 스키마가 동일해야 하며, A - B에서 A ⊇ B일 필요는 없습니다.
4. 최대값 구하기 (Find the Largest Account Balance)
관계대수에는 집계 함수가 없으므로, self-join과 차집합을 사용해 최대값을 구합니다.
Dup_acc ← account
less_Balance ← π balance (
account ⨝ account.balance < Dup_acc.balance Dup_acc
)
max_Balance ← π balance (account) − less_Balance
실전 예시: 학교 시스템
🔎 교수 이름과 그 교수가 가르치는 과목을 찾기
π name, course_id (
instructor ⨝ ID = teaches.ID
)
🔎 CS 학과에서 개설한 과목들의 course_id와 title 출력
π course_id, title (
σ dept_name = "CS" (course)
)
5. Outer Join과 Null의 의미
- Outer Join은 정보 손실을 막기 위해 한쪽 릴레이션을 기준으로 NULL을 채워줌
- Null은 보통 unknown 값으로 해석되며, 연산에 포함되면 결과가 NULL이 되는 등 연산을 방해할 수 있음
- Aggregate 연산에서는 NULL을 무시함
6. Division 연산 예시
문제: 모든 지점에 계좌가 있는 고객 찾기
r ← π customer-name, branch-name (depositor ⨝ account)
s ← π branch-name (branch)
r % s → 조건 만족하는 customer-name만 반환
문제: Downtown, Uptown 모두에 계좌가 있는 고객 찾기
- s를 리터럴 릴레이션으로 정의해야 정확
s ← { ('Downtown'), ('Uptown') }
r ← π customer-name, branch-name (depositor ⨝ account)
r % s
7. DB 시멘틱을 고려한 데이터 갱신
Deletion
account ← account - r2
depositor ← depositor - r3
→ 관계적 의미에 따라 연관된 릴레이션도 함께 삭제해야 일관성 유지
Insertion
→ 계좌 추가 시 depositor 테이블에도 같이 튜플 추가 필요
Update 예시
→ Projection 내에 수식도 포함 가능
account ← π account-number, balance × 1.05 (account)
마무리
관계대수는 단순한 SQL 쿼리보다 더 깊은 이해를 요구하지만, 데이터 질의의 논리 구조를 명확하게 설계할 수 있는 수단입니다. 실전 문제 해결과 쿼리 최적화를 위해선 이론과 함께 다양한 예제를 통한 훈련이 중요합니다.