外部キーにヌル値可能フィールドを使用しているため、実際には、想定どおりに正しく機能するシステムを構築できます。Accountsテーブルに行を挿入するには、null PrimaryContactIDを持つAccountsへの挿入を許可しない限り、Contactsテーブルに行が存在する必要があります。アカウント行がまだ存在しない状態で連絡先行を作成するには、ContactsテーブルのAccountID列をNULL可能にする必要があります。これにより、アカウントは連絡先を持たず、連絡先はアカウントを持たなくなります。おそらくこれは望ましいかもしれませんが、おそらくそうではありません。
そうは言っても、私の個人的な好みは次のセットアップをすることです。
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
オプションで指定されるため、アカウントごとに1つのプライマリ連絡先しか存在できません。
たとえば、すべての連絡先のリストを「プライマリ」ステータスを示す列で表示し、各アカウントのリストの上部にプライマリ連絡先を表示する場合、次のようにします。
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;