Cách Sử Dụng “Second Normal Form”
Trong bài viết này, chúng ta sẽ khám phá “Second Normal Form” (2NF) – một khái niệm quan trọng trong thiết kế cơ sở dữ liệu quan hệ. Bài viết cung cấp 20 ví dụ minh họa các bảng cơ sở dữ liệu và cách chúng được chuẩn hóa, cùng hướng dẫn chi tiết về ý nghĩa, cách áp dụng, quy tắc, và các lưu ý quan trọng.
Phần 1: Hướng dẫn sử dụng “Second Normal Form” và các lưu ý
1. Ý nghĩa cơ bản của “Second Normal Form”
“Second Normal Form” (2NF) là một giai đoạn chuẩn hóa trong thiết kế cơ sở dữ liệu. Một bảng ở dạng 2NF khi nó đáp ứng các điều kiện sau:
- Bảng phải ở dạng 1NF (First Normal Form).
- Tất cả các thuộc tính không khóa phải phụ thuộc đầy đủ (fully functionally dependent) vào khóa chính. Nói cách khác, không có thuộc tính không khóa nào phụ thuộc vào một phần của khóa chính.
Dạng liên quan: “First Normal Form” (1NF), “Third Normal Form” (3NF), “Boyce-Codd Normal Form” (BCNF).
Ví dụ:
- Bảng KHÔNG ở 2NF: Bảng có khóa chính phức hợp (ví dụ, {StudentID, CourseID}) và một thuộc tính (ví dụ, CourseName) chỉ phụ thuộc vào CourseID.
- Bảng Ở 2NF: Bảng sau khi đã tách thành hai bảng, một bảng chứa {CourseID, CourseName} và bảng còn lại chứa {StudentID, CourseID, Grade}.
2. Cách sử dụng “Second Normal Form”
a. Xác định khóa chính
- Xác định khóa chính của bảng. Nếu khóa chính là khóa đơn (chỉ có một thuộc tính), bảng tự động ở 2NF nếu nó ở 1NF.
Ví dụ: StudentID là khóa chính.
b. Xác định các phụ thuộc hàm
- Xác định tất cả các phụ thuộc hàm (functional dependencies) trong bảng.
Ví dụ: StudentID -> StudentName, CourseID -> CourseName, {StudentID, CourseID} -> Grade
c. Kiểm tra phụ thuộc một phần
- Kiểm tra xem có thuộc tính không khóa nào phụ thuộc vào một phần của khóa chính hay không (chỉ khi khóa chính là khóa phức hợp).
Ví dụ: Nếu CourseName chỉ phụ thuộc vào CourseID, thì có phụ thuộc một phần.
d. Tách bảng
- Nếu có phụ thuộc một phần, tách bảng thành hai hoặc nhiều bảng để loại bỏ phụ thuộc một phần.
Ví dụ: Tách bảng ban đầu thành bảng StudentCourses {StudentID, CourseID, Grade} và bảng Courses {CourseID, CourseName}.
e. Bảng biến đổi
Trạng thái | Bảng (ví dụ) | Vấn đề | Giải pháp |
---|---|---|---|
Trước 2NF | {StudentID, CourseID, CourseName, Grade} | CourseName phụ thuộc vào CourseID, là một phần của khóa chính. | Tách thành hai bảng: StudentCourses {StudentID, CourseID, Grade} và Courses {CourseID, CourseName}. |
Sau 2NF | StudentCourses {StudentID, CourseID, Grade} và Courses {CourseID, CourseName} | Không còn phụ thuộc một phần. | Các bảng đã ở 2NF. |
3. Một số cụm từ thông dụng liên quan
- Functional Dependency: Phụ thuộc hàm.
Ví dụ: CourseID determines CourseName (CourseID quyết định CourseName). - Partial Dependency: Phụ thuộc một phần.
Ví dụ: CourseName depends only on CourseID, part of the primary key {StudentID, CourseID}. - Normalization: Chuẩn hóa.
Ví dụ: Normalization to 2NF eliminates partial dependencies. (Chuẩn hóa về 2NF loại bỏ các phụ thuộc một phần.)
4. Lưu ý khi sử dụng “Second Normal Form”
a. Ngữ cảnh phù hợp
- Khi có khóa chính phức hợp: 2NF chỉ cần thiết khi khóa chính của bảng là một khóa phức hợp (bao gồm nhiều thuộc tính).
- Loại bỏ dư thừa dữ liệu: 2NF giúp giảm thiểu sự dư thừa dữ liệu và cải thiện tính nhất quán của cơ sở dữ liệu.
b. Phân biệt với các dạng chuẩn hóa khác
- 1NF vs 2NF: 1NF chỉ yêu cầu không có nhóm lặp, trong khi 2NF loại bỏ phụ thuộc một phần.
Ví dụ: Một bảng có thể ở 1NF nhưng không ở 2NF nếu có phụ thuộc một phần. - 2NF vs 3NF: 2NF loại bỏ phụ thuộc một phần, trong khi 3NF loại bỏ phụ thuộc bắc cầu.
Ví dụ: Một bảng có thể ở 2NF nhưng không ở 3NF nếu có phụ thuộc bắc cầu.
c. Thứ tự thực hiện
- Luôn đảm bảo bảng ở 1NF trước khi chuyển sang 2NF.
5. Những lỗi cần tránh
- Không xác định đúng khóa chính:
– Sai: Xác định sai khóa chính dẫn đến phân tích sai các phụ thuộc. - Bỏ qua phụ thuộc một phần:
– Sai: Không nhận ra và loại bỏ các phụ thuộc một phần. - Tách bảng không đúng cách:
– Sai: Tách bảng thành các bảng con không hợp lý, dẫn đến mất thông tin hoặc khó truy vấn.
6. Mẹo để ghi nhớ và sử dụng hiệu quả
- Tập trung vào khóa chính: Xác định rõ khóa chính và các thuộc tính liên quan.
- Vẽ sơ đồ phụ thuộc: Vẽ sơ đồ phụ thuộc hàm để dễ dàng nhận ra các phụ thuộc một phần.
- Thực hành: Áp dụng 2NF vào các bảng cơ sở dữ liệu thực tế để làm quen với quy trình.
Phần 2: Ví dụ sử dụng “Second Normal Form” và các dạng liên quan
Ví dụ minh họa
Dưới đây là các ví dụ về cách áp dụng Second Normal Form để chuẩn hóa các bảng cơ sở dữ liệu:
- Bảng ban đầu: Orders (OrderID, CustomerID, CustomerName, OrderDate). CustomerName chỉ phụ thuộc vào CustomerID. Tách thành Customers (CustomerID, CustomerName) và Orders (OrderID, CustomerID, OrderDate).
- Bảng ban đầu: OrderDetails (OrderID, ProductID, ProductName, Quantity). ProductName chỉ phụ thuộc vào ProductID. Tách thành Products (ProductID, ProductName) và OrderDetails (OrderID, ProductID, Quantity).
- Bảng ban đầu: Employees (EmployeeID, DepartmentID, DepartmentName, Salary). DepartmentName chỉ phụ thuộc vào DepartmentID. Tách thành Departments (DepartmentID, DepartmentName) và Employees (EmployeeID, DepartmentID, Salary).
- Bảng ban đầu: Students (StudentID, CourseID, CourseName, Grade). CourseName chỉ phụ thuộc vào CourseID. Tách thành Courses (CourseID, CourseName) và Students (StudentID, CourseID, Grade).
- Bảng ban đầu: Projects (ProjectID, EmployeeID, EmployeeName, HoursWorked). EmployeeName chỉ phụ thuộc vào EmployeeID. Tách thành Employees (EmployeeID, EmployeeName) và Projects (ProjectID, EmployeeID, HoursWorked).
- Bảng ban đầu: Customers (CustomerID, AddressID, AddressLine1, City). AddressLine1 và City chỉ phụ thuộc vào AddressID. Tách thành Addresses (AddressID, AddressLine1, City) và Customers (CustomerID, AddressID).
- Bảng ban đầu: Books (BookID, AuthorID, AuthorName, PublicationYear). AuthorName chỉ phụ thuộc vào AuthorID. Tách thành Authors (AuthorID, AuthorName) và Books (BookID, AuthorID, PublicationYear).
- Bảng ban đầu: Songs (SongID, ArtistID, ArtistName, Duration). ArtistName chỉ phụ thuộc vào ArtistID. Tách thành Artists (ArtistID, ArtistName) và Songs (SongID, ArtistID, Duration).
- Bảng ban đầu: Products (ProductID, CategoryID, CategoryName, Price). CategoryName chỉ phụ thuộc vào CategoryID. Tách thành Categories (CategoryID, CategoryName) và Products (ProductID, CategoryID, Price).
- Bảng ban đầu: Movies (MovieID, DirectorID, DirectorName, ReleaseYear). DirectorName chỉ phụ thuộc vào DirectorID. Tách thành Directors (DirectorID, DirectorName) và Movies (MovieID, DirectorID, ReleaseYear).
- Bảng ban đầu: Appointments (AppointmentID, PatientID, PatientName, AppointmentDate). PatientName chỉ phụ thuộc vào PatientID. Tách thành Patients (PatientID, PatientName) và Appointments (AppointmentID, PatientID, AppointmentDate).
- Bảng ban đầu: Lectures (LectureID, ProfessorID, ProfessorName, LectureTime). ProfessorName chỉ phụ thuộc vào ProfessorID. Tách thành Professors (ProfessorID, ProfessorName) và Lectures (LectureID, ProfessorID, LectureTime).
- Bảng ban đầu: Classes (ClassID, RoomID, RoomName, ClassTime). RoomName chỉ phụ thuộc vào RoomID. Tách thành Rooms (RoomID, RoomName) và Classes (ClassID, RoomID, ClassTime).
- Bảng ban đầu: Events (EventID, VenueID, VenueName, EventDate). VenueName chỉ phụ thuộc vào VenueID. Tách thành Venues (VenueID, VenueName) và Events (EventID, VenueID, EventDate).
- Bảng ban đầu: Recipes (RecipeID, IngredientID, IngredientName, Quantity). IngredientName chỉ phụ thuộc vào IngredientID. Tách thành Ingredients (IngredientID, IngredientName) và Recipes (RecipeID, IngredientID, Quantity).
- Bảng ban đầu: Tickets (TicketID, EventID, EventName, TicketPrice). EventName chỉ phụ thuộc vào EventID. Tách thành Events (EventID, EventName) và Tickets (TicketID, EventID, TicketPrice).
- Bảng ban đầu: Shipments (ShipmentID, ShipperID, ShipperName, ShipmentDate). ShipperName chỉ phụ thuộc vào ShipperID. Tách thành Shippers (ShipperID, ShipperName) và Shipments (ShipmentID, ShipperID, ShipmentDate).
- Bảng ban đầu: Payments (PaymentID, CustomerID, CustomerName, PaymentAmount). CustomerName chỉ phụ thuộc vào CustomerID. Tách thành Customers (CustomerID, CustomerName) và Payments (PaymentID, CustomerID, PaymentAmount).
- Bảng ban đầu: Subscriptions (SubscriptionID, MagazineID, MagazineName, SubscriptionDate). MagazineName chỉ phụ thuộc vào MagazineID. Tách thành Magazines (MagazineID, MagazineName) và Subscriptions (SubscriptionID, MagazineID, SubscriptionDate).
- Bảng ban đầu: Deliveries (DeliveryID, CourierID, CourierName, DeliveryDate). CourierName chỉ phụ thuộc vào CourierID. Tách thành Couriers (CourierID, CourierName) và Deliveries (DeliveryID, CourierID, DeliveryDate).