Có một kỹ thuật được gọi là tạo phiên bản đã tồn tại trong nhiều năm nhưng phần lớn không thể hoạt động được vì một số lý do. Tuy nhiên, có một kỹ thuật tương tự mà tôi gọi là Version Normal Form mà tôi thấy rất hữu ích. Đây là một ví dụ sử dụng bảng Nhân viên.
Đầu tiên, bảng tĩnh được tạo. Đây là bảng thực thể chính và nó chứa dữ liệu tĩnh về thực thể. Dữ liệu tĩnh là dữ liệu dự kiến sẽ không thay đổi trong suốt thời gian tồn tại của thực thể, chẳng hạn như ngày sinh.
create table Employees(
ID int auto_generated primary key,
FirstName varchar( 32 ),
Hiredate date not null,
TermDate date, -- last date worked
Birthdate date,
... -- other static data
);
Điều quan trọng là nhận ra có một mục nhập cho mỗi nhân viên, giống như với bất kỳ bảng nào như vậy.
Sau đó, bảng phiên bản được liên kết. Điều này thiết lập mối quan hệ 1 m với bảng tĩnh vì có thể có một số phiên bản cho một nhân viên.
create table Employee_versions(
ID int not null,
EffDate date not null,
char( 1 ) IsWorking not null default true,
LastName varchar( 32 ), -- because employees can change last name
PayRate currency not null,
WorkDept int references Depts( ID ),
..., -- other changable data
constraint PK_EmployeeV primary key( ID, EffDate )
);
Trong bảng phiên bản, lưu ý có ngày có hiệu lực nhưng không có trường không còn hiệu lực phù hợp. Điều này là do khi một phiên bản có hiệu lực, nó vẫn có hiệu lực cho đến khi được thay thế bằng phiên bản tiếp theo. Sự kết hợp giữa ID và EffDate phải là duy nhất để không thể có hai xác minh cho cùng một nhân viên đang hoạt động cùng một lúc, cũng như không thể có khoảng cách giữa thời điểm một phiên bản kết thúc và khi phiên bản tiếp theo bắt đầu.
Hầu hết các truy vấn sẽ muốn biết phiên bản hiện tại của dữ liệu nhân viên. Điều này được cung cấp bằng cách tham gia hàng tĩnh cho nhân viên với phiên bản hiện có hiệu lực. Điều này có thể được tìm thấy với truy vấn sau:
select ...
from Employees e
join Employee_versions v1
on v1.ID = e.ID
and v1.EffDate =(
select Max( v2.EffDate )
from EmployeeVersions v2
where v2.ID = v1.ID
and v2.EffDate <= NOW()
)
where e.ID = :EmpID;
Điều này trả về một và chỉ một phiên bản đã bắt đầu trong quá khứ gần đây nhất. Sử dụng bất đẳng thức <=trong kiểm tra ngày (v2.EffDate <= NOW()
) cho phép các ngày có hiệu lực trong tương lai. Giả sử bạn biết một nhân viên mới sẽ bắt đầu vào ngày đầu tiên của tháng tới hoặc dự kiến tăng lương vào ngày 13 của tháng tiếp theo, dữ liệu này có thể được chèn trước thời hạn. Các mục nhập "được tải trước" như vậy sẽ bị bỏ qua.
Đừng để truy vấn con đến với bạn. Tất cả các trường tìm kiếm đều được lập chỉ mục nên kết quả khá nhanh.
Có rất nhiều sự linh hoạt với thiết kế này. Truy vấn trên trả về dữ liệu mới nhất của tất cả nhân viên, hiện tại và quá khứ. Bạn có thể kiểm tra TermDate
lĩnh vực để chỉ có được nhân viên hiện tại. Trên thực tế, vì nhiều nơi trong ứng dụng của bạn sẽ chỉ quan tâm đến thông tin hiện tại của nhân viên hiện tại, nên truy vấn đó sẽ tạo ra một cái nhìn tốt (bỏ qua where
cuối cùng mệnh đề). Không cần ứng dụng biết các phiên bản như vậy tồn tại.
Nếu bạn có một ngày cụ thể và bạn muốn xem dữ liệu có hiệu lực vào thời điểm đó, hãy thay đổi v2.EffDate <= NOW()
trong truy vấn con tới v2.EffDate <= :DateOfInterest
.
Bạn có thể tìm thêm thông tin chi tiết trong bản trình bày slide tại đây và một tài liệu chưa hoàn chỉnh tại đây.
Để thể hiện một chút khả năng mở rộng của thiết kế, hãy lưu ý rằng có một IsWorking
chỉ báo trong bảng phiên bản cũng như ngày kết thúc trong bảng tĩnh. Khi một nhân viên rời công ty, ngày cuối cùng được chèn vào bảng tĩnh và một bản sao của phiên bản mới nhất với IsWorking
đặt thành false
được chèn vào bảng phiên bản.
Việc nhân viên rời bỏ công ty một thời gian rồi được thuê lại là điều khá phổ biến. Chỉ với ngày trong bảng tĩnh, mục nhập có thể được kích hoạt lại chỉ bằng cách đặt ngày đó trở lại NULL. Nhưng một truy vấn "nhìn lại" bất kỳ lúc nào khi người đó không còn là nhân viên sẽ trả về một kết quả. Sẽ không có dấu hiệu nào cho thấy họ đã rời công ty. Nhưng một phiên bản có IsWorking
=false khi rời công ty và IsWorking
=true khi trở lại công ty sẽ cho phép kiểm tra giá trị đó tại thời điểm quan tâm và bỏ qua nhân viên khi họ không còn là nhân viên ngay cả khi họ quay lại sau đó.