Da Sie nullfähige Felder für die Fremdschlüssel verwenden, können Sie tatsächlich ein System erstellen, das so funktioniert, wie Sie es sich vorstellen. Um Zeilen in die Accounts-Tabelle einzufügen, muss in der Contacts-Tabelle eine Zeile vorhanden sein, sofern Sie keine Einfügungen in Accounts mit einer PrimaryContactID von Null zulassen. Um eine Kontaktzeile zu erstellen, ohne dass bereits eine Kontozeile vorhanden ist, müssen Sie zulassen, dass die Spalte "AccountID" in der Tabelle "Kontakte" nullwertfähig ist. Auf diese Weise können Konten keine Kontakte und Kontakte kein Konto haben. Vielleicht ist das wünschenswert, vielleicht auch nicht.
Persönlich würde ich jedoch folgendes Setup bevorzugen:
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;
Dies bietet die Möglichkeit:
- Zeichnen Sie die Beziehungen zwischen Kontakten und Konten anhand einer Querverweistabelle klar ab, wie es Pieter in seiner Antwort empfiehlt
- Bewahren Sie die referenzielle Integrität auf eine gesunde, nicht kreisförmige Weise auf.
- Stellen Sie über den Index eine hochgradig verwaltbare Liste der primären Kontakte
IX_AccountsContactsXRef_Primary
bereit. Dieser Index enthält einen Filter, sodass er nur auf Plattformen funktioniert, die diesen unterstützen. Da dieser Index mit der UNIQUE
Option angegeben wird, kann es für jedes Konto immer nur einen einzigen Hauptkontakt geben.
Wenn Sie beispielsweise eine Liste aller Kontakte anzeigen möchten, wobei eine Spalte den "primären" Status anzeigt und die primären Kontakte für jedes Konto oben in der Liste angezeigt werden, können Sie Folgendes tun:
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;
Der gefilterte Index verhindert das Einfügen von mehr als einem primären Kontakt pro Konto und bietet gleichzeitig eine schnelle Methode zum Zurückgeben einer Liste primärer Kontakte. Man kann sich leicht eine andere Spalte IsActive
mit einem nicht eindeutigen gefilterten Index vorstellen , um den Verlauf der Kontakte pro Konto aufrechtzuerhalten, auch wenn dieser Kontakt nicht mehr mit dem Konto verknüpft ist:
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;