Thứ Tư, 10 tháng 2, 2016

Phát triển HTTT kế toán bằng MS Access - Chương 2 - Dạng chuẩn hai

James Perry, Richard Newmark


Chương 2
Cơ sở dữ liệu và hệ thống kế toán


Dạng chuẩn hai


Bảng ở dạng chuẩn một có thể đặt vào hệ cơ sở dữ liệu quan hệ, nhưng nhiều trường hợp dạng chuẩn một không đủ ngăn chặn nhiều vấn đề. Chẳng hạn, Hình 2.11 cho ví dụ một số dòng thuộc bảng khách hàng ở dạng chuẩn một. Lược đồ bảng là:

        tblCustomer(CustID, CompanyName, PhoneNumber, Contact, InvoiceID, Total)


Hình 2.11. Các dòng ví dụ thuộc bảng khách hàng ở dạng chuẩn một (1NF).

Bảng khách hàng chứa thông tin khách hàng gồm mã số khách hàng, tên công ty, điện thoại, và người liên lạc. Hai cột cuối ký hiệu mã hóa đơn khách hàng và tổng tiền. Hai cột CustID và InvoiceID tạo nên khóa chính của bảng. Cả hai cần để truy xuất một dòng.

Có một số vấn đề tiềm tàng trong bảng khách hàng 1NF. Giả sử bảng khách hàng là nơi duy nhất lưu trữ thông tin khách hàng chẳng hạn địa chỉ và tên. Hơn nữa, giả sử một khách hàng mới đã trả tiền trước  một đơn đặt hàng. Thiết kế hiện thời không cho phép thêm vào khách hàng như thế, vì InvoiceID bị trống. Khi một thuộc tính bị trống, hay không có giá trị, nó bằng null. Thuộc tính InvoiceID không thể bằng null, vì khóa chính không thể bằng null hay gồm một thuộc tính null nếu đó là khóa chính phức hợp. Tình trạng bất khả bổ sung một bản ghi gọi là dị thường khi thêm (insertion anomaly).

Xét kịch bản sau. Cavco Industries trả tiền 2 hóa đơn, mã số 214123 và 214460 (xem hình 2.11, dòng 2 và 3), đưa tiền nợ của họ về 0. Hai dòng ứng với Cavco Industries được loại khỏi tblCustomer. Không chỉ 2 dòng hóa đơn bị loại, mà mã khách hàng, tên, điện thoại, và người liên hệ cũng bị xóa. Như vậy thao tác xóa tác động nhiều hơn mong muốn; bạn hoàn toàn bị mất thông tin khách hàng. Danh mục địa chỉ của bạn bị hủy hoại! Tình huống dự kiến trước này gọi là dị thường khi xóa (deletion anomaly).

Bảng tblCustomer ở Hình 2.11 chứa nhiều thông tin thừa. Chẳng hạn, các giá trị CustID, Customer, và CustPhone bị trùng mỗi khi xuất hóa đơn mới cho khách hàng quen. Khách hàng Richard Muck bị nhập 2 lần, khách hàng David Gibson cũng vậy. Thật may khi tên và điện thoại khách hàng được nhập 2 lần đều đúng. Muốn đổi tên khách hàng, bạn phải tìm trên toàn cơ sở dữ liệu rồi đổi từng tên một. Thật là phí thời gian. Ví dụ nhỏ này cho thấy bảng ở dạng chuẩn một chứa dữ liệu dư thừa.

Thay đổi cấu trúc bảng và chuyển về dạng chuẩn hai có thể ngăn những dị thường này. Một bảng (quan hệ) ở dạng chuẩn hai (second normal form, 2NF) nếu bảng đó ở dạng chuẩn một và không có thuộc tính phi khóa nào phụ thuộc chỉ một phần vào khóa chính. Nghĩa là, dạng chuẩn hai yêu cầu từng thuộc tính phi khóa phải phụ thuộc hoàn toàn vào khóa chính, không chỉ một phần khóa chính. Qui tắc này chỉ áp dụng khi có khóa chính phức hợp – tức khóa chính chứa nhiều hơn một cột bảng.

Thuộc tính Total trong bảng khách hàng ở Hình 2.11 vi phạm định nghĩa 2NF. Giá trị Total được xác định qua một phần khóa chính là InvoiceID. Ta nói Total phụ thuộc hàm (functionally dependent) vào InvoiceID vì một giá trị cụ thể của InvoiceID sẽ xác định một giá trị Total đơn lẻ. Mặt khác, Total không phụ thuộc vào thuộc tính và cũng là một phần khóa chính CustID, và tổng giá trị hóa đơn thay đổi theo hóa đơn nên chẳng có quan hệ nào giữa Total và một khách hàng cụ thể. Hơn nữa, từng thuộc tính Customer và CustPhone lại phụ thuộc hàm vào một phần khóa chính CustID. Hai tập phụ thuộc hàm này được minh họa ở Hình 2.12.


Hình 2.12. Các phụ thuộc hàm trong bảng khách hàng.

Các mũi tên đi từ khóa chính đến thuộc tính kia. Chẳng hạn, mũi tên từ CustID đến Customer nghĩa là CustID xác định Customer, hay CustID là định thức (determinant) của Customer. Rõ ràng là ta có thể sửa chữa vấn đề này bằng cách phân tblCustomer thành 2 bảng. Dĩ nhiên, ta phải ký hiệu quan hệ giữa 2 bảng này bằng cách thêm một thuộc tính phụ - khóa ngoại – để nối 2 bảng trên khóa CustID. Bạn có thể tái cấu trúc tblCustomer và bảng liên quan tblInvoice để chúng ở dạng chuẩn hai theo thiết kế sau:

        tblCustomer(CustID, Customer, CustPhone)
        tblInvoice(InvoiceID, CustID, Total)

Trong thiết kế này, trường CustID trong tblInvoice là khóa ngoại trỏ đến tblCustomer.

Không có nhận xét nào:

Đăng nhận xét