Unary Relationship (Mối quan hệ đệ quy / tự tham chiếu) là mối quan hệ giữa các instance (thể hiện) của **chính một entity type (loại thực thể)**. One-to-Many Unary** nghĩa là một instance đóng vai "cha" (parent) liên kết với nhiều instance đóng vai "con" (child), nhưng tất cả đều thuộc cùng một bảng.
Ví dụ kinh điển: Employee - Manager
Bảng Employee:
| Emp_ID (PK) | Emp_Name | Manager_ID (FK) |
|---|---|---|
| 1 | CEO | NULL |
| 2 | CTO | 1 |
| 3 | Dev Lead | 2 |
| 4 | Dev A | 3 |
| 5 | Dev B | 3 |
Manager_IDlà **Foreign Key** tự tham chiếu vềEmp_IDcủa cùng bảng.- Một Manager (Emp_ID=2) quản lý nhiều Employee (Emp_ID=3,4,5...).
- CEO (Emp_ID=1) không có Manager ->
Manager_ID = NULL.
Hai vai trò (Role Groups) trong quan hệ
| Vai trò | Mô tả | Ví dụ |
|---|---|---|
| Manager (Parent/Supervisor) | Instance đóng vai "quản lý", "cha" | CEO, CTO, Dev Lead |
| Employee (Subordinate/Child) | Instance đóng vai "cấp dưới", "con" | Tất cả nhân viên (kể cả Manager cũng là Employee của người khác) |
Đặc thù tham gia (Participation Constraints)
1. Optional - Mandatory (Thường gặp nhất)
- Manager role: Optional. Không phải Employee nào cũng là Manager (CEO không quản lý ai? CEO quản lý CTO. Nhưng Dev A, Dev B không quản lý ai). Có instance không tham gia vai Manager.
- Employee role: Mandatory. Mọi instance **phải** là Employee (của ai đó), **TRỪ** instance gốc (Root/CEO). → **Vi phạm** mandatory participation tại root.
Giải pháp: Cho phép Manager_ID NULL cho root. Khi đó Employee role thực tế là **Optional** cho root, Mandatory cho các instance khác. Mô hình thường là Optional-Optional hoặc Optional-Mandatory với ngoại lệ root.
2. Optional - Optional
- Cả hai vai trò đều Optional.
- Instance có thể không là Manager (không có cấp dưới).
- Instance có thể không có Manager (root/CEO).
- Hợp lý nhất cho cấu trúc tổ chức thực tế.
3. Mandatory - Mandatory (Hiếm, chỉ lý thuyết)
- Mọi instance PHẢI vừa là Manager (có ít nhất 1 cấp dưới) VỪA là Employee (có Manager).
- → Vô tận hoặc vòng tròn (cycle). Không thực tế cho org chart.
ER Diagram (Sơ đồ ER) ký hiệu
Employee (Entity) | | 1 (Manager) M (Employee) |----------------------| | Manages / Reports_to | |______________________| (Recursive relationship)
Triển khai SQL
CREATE TABLE Employee (
Emp_ID INT PRIMARY KEY,
Emp_Name VARCHAR(100) NOT NULL,
Manager_ID INT,
FOREIGN KEY (Manager_ID) REFERENCES Employee(Emp_ID)
ON DELETE SET NULL -- Xóa manager -> cấp dưới thành NULL (hoặc CASCADE nếu quy định)
ON UPDATE CASCADE
);
-- Index cho FK để join nhanh
CREATE INDEX idx_emp_manager ON Employee(Manager_ID);
Truy vấn đệ quy (Recursive Query) - CTE
Lấy toàn bộ cấp dưới của một Manager (PostgreSQL, SQL Server, Oracle, MySQL 8+):
WITH RECURSIVE Subordinates AS ( -- Anchor: Manager trực tiếp SELECT Emp_ID, Emp_Name, Manager_ID, 1 AS Level FROM Employee WHERE Manager_ID = 2 -- CTO UNION ALL -- Recursive: Cấp dưới của cấp dưới SELECT e.Emp_ID, e.Emp_Name, e.Manager_ID, s.Level + 1 FROM Employee e INNER JOIN Subordinates s ON e.Manager_ID = s.Emp_ID ) SELECT * FROM Subordinates;
Các ví dụ Unary One-to-Many khác
- Category/Menu đệ quy: Danh mục cha/con (CategoryID, ParentCategoryID).
- Bill of Materials (BOM): Thành phần cha/con sản xuất (PartID, ParentPartID).
- File System: Thư mục/Folder (FolderID, ParentFolderID).
- Comment/Reply: Bình luận cha/con (CommentID, ParentCommentID).
Lưu ý thiết kế
- Luôn index FK (
Manager_ID) để truy vấn con nhanh. - Tránh chu trình (cycle): A quản lý B, B quản lý A. Dùng trigger hoặc application logic kiểm tra.
- Cân nhắc
path enumeration(materialized path:1/2/3/4) hoặcnested setcho read-heavy hierarchy. - Phân biệt rõ Role Name: "Manages" vs "Reports To" để không nhầm lẫn direction.