SQL Server 2008 und höher
Filtern Sie einfach einen eindeutigen Index:
CREATE UNIQUE NONCLUSTERED INDEX UQ_Party_SamAccountName
ON dbo.Party(SamAccountName)
WHERE SamAccountName IS NOT NULL;
In niedrigeren Versionen ist eine materialisierte Ansicht immer noch nicht erforderlich
Für SQL Server 2005 und früher können Sie dies ohne Ansicht tun. Ich habe gerade einer meiner Tabellen eine eindeutige Einschränkung hinzugefügt, nach der Sie fragen. Da ich die Eindeutigkeit in der Spalte möchte SamAccountName
, aber mehrere NULL-Werte zulassen möchte, habe ich eine materialisierte Spalte anstelle einer materialisierten Ansicht verwendet:
ALTER TABLE dbo.Party ADD SamAccountNameUnique
AS (Coalesce(SamAccountName, Convert(varchar(11), PartyID)))
ALTER TABLE dbo.Party ADD CONSTRAINT UQ_Party_SamAccountName
UNIQUE (SamAccountNameUnique)
Sie müssen lediglich etwas in die berechnete Spalte einfügen, das in der gesamten Tabelle garantiert eindeutig ist, wenn die tatsächlich gewünschte eindeutige Spalte NULL ist. In diesem Fall PartyID
handelt es sich um eine Identitätsspalte, und numerisch zu sein wird niemals mit einer übereinstimmen. Daher SamAccountName
hat es bei mir funktioniert. Sie können Ihre eigene Methode ausprobieren - stellen Sie sicher, dass Sie die Domäne Ihrer Daten verstehen, damit keine Möglichkeit besteht, sich mit realen Daten zu überschneiden. Das könnte so einfach sein, als würde man ein Unterscheidungsmerkmal wie dieses voranstellen:
Coalesce('n' + SamAccountName, 'p' + Convert(varchar(11), PartyID))
Selbst wenn es PartyID
eines Tages nicht numerisch wurde und mit einem zusammenfallen könnte SamAccountName
, spielt es jetzt keine Rolle mehr.
Beachten Sie, dass das Vorhandensein eines Index einschließlich der berechneten Spalte implizit dazu führt, dass jedes Ausdrucksergebnis mit den anderen Daten in der Tabelle auf der Festplatte gespeichert wird, was zusätzlichen Speicherplatz beansprucht.
Beachten Sie, dass Sie, wenn Sie keinen Index möchten, dennoch CPU sparen können, indem Sie den Ausdruck auf der Festplatte vorberechnen, indem Sie das Schlüsselwort PERSISTED
am Ende der Definition des Spaltenausdrucks hinzufügen .
Verwenden Sie in SQL Server 2008 und höher auf jeden Fall stattdessen die gefilterte Lösung, wenn Sie können!
Kontroverse
Bitte beachten Sie, dass einige Datenbankprofis dies als einen Fall von "Ersatz-NULL-Werten" betrachten, die definitiv Probleme haben (hauptsächlich aufgrund von Problemen beim Versuch, festzustellen, ob etwas ein realer Wert oder ein Wert ist Ersatzwert für fehlende Daten ist ; es kann auch Probleme geben mit der Anzahl der Nicht-NULL-Ersatzwerte, die sich wie verrückt multiplizieren).
Ich glaube jedoch, dass dieser Fall anders ist. Die berechnete Spalte, die ich hinzufüge, wird niemals verwendet, um etwas zu bestimmen. Es hat keine eigene Bedeutung und codiert keine Informationen, die nicht bereits separat in anderen, ordnungsgemäß definierten Spalten gefunden wurden. Es sollte niemals ausgewählt oder verwendet werden.
Meine Geschichte ist also, dass dies kein Ersatz-NULL ist, und ich bleibe dabei! Da wir den Nicht-NULL-Wert nicht für einen anderen Zweck als zum Trick des UNIQUE
Index zum Ignorieren von NULL-Werten verwenden möchten, weist unser Anwendungsfall keines der Probleme auf, die bei der normalen NULL-Ersatzerstellung auftreten.
Trotzdem habe ich kein Problem damit, stattdessen eine indizierte Ansicht zu verwenden - aber es bringt einige Probleme mit sich, wie z. B. die Anforderung der Verwendung SCHEMABINDING
. Viel Spaß beim Hinzufügen einer neuen Spalte zu Ihrer Basistabelle (Sie müssen mindestens den Index löschen und dann die Ansicht löschen oder die Ansicht so ändern, dass sie nicht an ein Schema gebunden ist). Siehe die vollständige (lange) Liste der Anforderungen zum Erstellen einer indizierten Ansicht in SQL Server (2005) (auch spätere Versionen), (2000) .
Aktualisieren
Wenn Ihre Spalte numerisch ist, besteht möglicherweise die Herausforderung, sicherzustellen, dass die Verwendung der eindeutigen Einschränkung Coalesce
nicht zu Kollisionen führt. In diesem Fall gibt es einige Optionen. Eine könnte darin bestehen, eine negative Zahl zu verwenden, um die "Ersatz-NULL" nur in den negativen Bereich und die "realen Werte" nur in den positiven Bereich zu setzen. Alternativ könnte das folgende Muster verwendet werden. In der Tabelle Issue
(wo IssueID
ist die PRIMARY KEY
) kann es eine geben oder nicht TicketID
, aber wenn es eine gibt, muss sie eindeutig sein.
ALTER TABLE dbo.Issue ADD TicketUnique
AS (CASE WHEN TicketID IS NULL THEN IssueID END);
ALTER TABLE dbo.Issue ADD CONSTRAINT UQ_Issue_Ticket_AllowNull
UNIQUE (TicketID, TicketUnique);
Wenn IssueID 1 über Ticket 123 verfügt, gilt die UNIQUE
Einschränkung für Werte (123, NULL). Wenn IssueID 2 kein Ticket hat, ist es eingeschaltet (NULL, 2). Einige Überlegungen werden zeigen, dass diese Einschränkung für keine Zeile in der Tabelle dupliziert werden kann und dennoch mehrere NULL-Werte zulässt.