เนื่องจากคุณใช้เขตข้อมูล null สำหรับคีย์ต่างประเทศคุณจึงสามารถสร้างระบบที่ทำงานได้อย่างถูกต้องตามที่คุณคาดคิด ในการแทรกแถวลงในตารางบัญชีคุณต้องมีแถวอยู่ในตารางรายชื่อเว้นแต่ว่าคุณจะอนุญาตให้แทรกลงในบัญชีที่มี null PrimaryContactID ในการสร้างแถวที่ติดต่อโดยที่ไม่มีแถวบัญชีอยู่คุณต้องอนุญาตให้คอลัมน์บัญชี ID ในตารางที่ติดต่อว่างเปล่า สิ่งนี้อนุญาตให้บัญชีไม่มีผู้ติดต่อและอนุญาตให้ผู้ติดต่อไม่มีบัญชี บางทีนี่อาจเป็นที่ต้องการ
ต้องบอกว่าการตั้งค่าส่วนตัวของฉันจะต้องมีการตั้งค่าต่อไปนี้:
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;
สิ่งนี้ให้ความสามารถในการ:
- อธิบายความสัมพันธ์ระหว่างผู้ติดต่อและบัญชีอย่างชัดเจนผ่านตารางตัวอ้างอิงโยงตามวิธีที่ Pieter แนะนำในคำตอบของเขา
- รักษาความสมบูรณ์ของการอ้างอิงในลักษณะที่ไม่เป็นวงกลม
- จัดทำรายการผู้ติดต่อหลักที่สามารถดูแลรักษาได้อย่างดีผ่าน
IX_AccountsContactsXRef_Primary
ดัชนี ดัชนีนี้มีตัวกรองดังนั้นจะใช้งานได้บนแพลตฟอร์มที่รองรับเท่านั้น เนื่องจากดัชนีนี้ถูกระบุด้วยUNIQUE
ตัวเลือกจึงอาจมีผู้ติดต่อหลักเพียงรายเดียวเท่านั้นสำหรับแต่ละบัญชี
ตัวอย่างเช่นหากคุณต้องการแสดงรายชื่อผู้ติดต่อทั้งหมดพร้อมคอลัมน์แสดงสถานะ "หลัก" แสดงผู้ติดต่อหลักที่ด้านบนของรายการสำหรับแต่ละบัญชีคุณสามารถทำได้:
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;
ดัชนีที่กรองจะป้องกันการแทรกที่อยู่ติดต่อหลักมากกว่าหนึ่งรายการต่อบัญชีในขณะเดียวกันก็ให้วิธีการที่รวดเร็วในการส่งคืนรายชื่อผู้ติดต่อหลัก เราสามารถนึกภาพคอลัมน์อื่นได้ง่ายIsActive
ด้วยดัชนีที่ไม่ซ้ำกันกรองเพื่อรักษาประวัติผู้ติดต่อต่อบัญชีแม้หลังจากผู้ติดต่อนั้นจะไม่เชื่อมโยงกับบัญชีอีกต่อไป:
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;