Vì bạn đang sử dụng các trường nullable cho các khóa ngoại, trên thực tế, bạn có thể xây dựng một hệ thống hoạt động chính xác theo cách bạn hình dung nó. Để chèn các hàng vào bảng Tài khoản, bạn cần phải có một hàng trong bảng Danh bạ trừ khi bạn cho phép chèn vào Tài khoản có null PrimaryContactID. Để tạo một hàng liên hệ mà chưa có hàng Tài khoản, bạn phải cho phép cột AccountID trong bảng Danh bạ là không thể. Điều này cho phép Tài khoản không có liên hệ và cho phép Danh bạ không có tài khoản. Có lẽ đây là mong muốn, có lẽ không.
Có nói rằng, sở thích cá nhân của tôi sẽ có các thiết lập sau:
CREATE TABLE dbo.Accounts
(
AccountID INT NOT NULL
CONSTRAINT PK_Accounts
PRIMARY KEY CLUSTERED
IDENTITY(1,1)
, AccountName VARCHAR(255)
);
CREATE TABLE dbo.Contacts
(
ContactID INT NOT NULL
CONSTRAINT PK_Contacts
PRIMARY KEY CLUSTERED
IDENTITY(1,1)
, ContactName VARCHAR(255)
);
CREATE TABLE dbo.AccountsContactsXRef
(
AccountsContactsXRefID INT NOT NULL
CONSTRAINT PK_AccountsContactsXRef
PRIMARY KEY CLUSTERED
IDENTITY(1,1)
, AccountID INT NOT NULL
CONSTRAINT FK_AccountsContactsXRef_AccountID
FOREIGN KEY REFERENCES dbo.Accounts(AccountID)
, ContactID INT NOT NULL
CONSTRAINT FK_AccountsContactsXRef_ContactID
FOREIGN KEY REFERENCES dbo.Contacts(ContactID)
, IsPrimary BIT NOT NULL
CONSTRAINT DF_AccountsContactsXRef
DEFAULT ((0))
, CONSTRAINT UQ_AccountsContactsXRef_AccountIDContactID
UNIQUE (AccountID, ContactID)
);
CREATE UNIQUE INDEX IX_AccountsContactsXRef_Primary
ON dbo.AccountsContactsXRef(AccountID, IsPrimary)
WHERE IsPrimary = 1;
Điều này cung cấp khả năng:
- Phân định rõ ràng mối quan hệ giữa các liên hệ và tài khoản thông qua bảng tham chiếu chéo theo cách mà Pieter đề xuất trong câu trả lời của mình
- Duy trì tính toàn vẹn tham chiếu một cách hợp lý, không tuần hoàn.
- Cung cấp cho một danh sách duy trì cao các liên hệ chính thông qua
IX_AccountsContactsXRef_Primary
chỉ mục. Chỉ mục này chứa bộ lọc, vì vậy nó sẽ chỉ hoạt động trên các nền tảng hỗ trợ chúng. Vì chỉ mục này được chỉ định với UNIQUE
tùy chọn, nên chỉ có thể có một liên hệ chính duy nhất cho mỗi tài khoản.
Ví dụ: nếu bạn muốn hiển thị danh sách tất cả các liên hệ, với một cột biểu thị trạng thái "chính", hiển thị các liên hệ chính ở đầu danh sách cho mỗi Tài khoản, bạn có thể làm:
SELECT A.AccountName
, C.ContactName
, XR.IsPrimary
FROM dbo.Accounts A
INNER JOIN dbo.AccountsContactsXRef XR ON A.AccountID = XR.AccountID
INNER JOIN dbo.Contacts C ON XR.ContactID = C.ContactID
ORDER BY A.AccountName
, XR.IsPrimary DESC
, C.ContactName;
Chỉ mục được lọc ngăn không cho chèn nhiều hơn một liên hệ chính trên mỗi tài khoản, đồng thời cung cấp phương thức nhanh chóng trả về danh sách các liên hệ chính. Người ta có thể dễ dàng tưởng tượng một cột khác, IsActive
với chỉ mục được lọc không duy nhất để duy trì lịch sử liên hệ trên mỗi tài khoản, ngay cả sau khi liên hệ đó không còn được liên kết với tài khoản:
ALTER TABLE dbo.AccountsContactsXRef
ADD IsActive BIT NOT NULL
CONSTRAINT DF_AccountsContactsXRef_IsActive
DEFAULT ((1));
CREATE INDEX IX_AccountsContactsXRef_IsActive
ON dbo.AccountsContactsXRef(IsActive)
WHERE IsActive = 1;