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
Bei SQL Server 2005 und früheren Versionen können Sie dies ohne eine Ansicht tun. Ich habe gerade eine eindeutige Einschränkung, wie Sie es wünschen, zu einer meiner Tabellen hinzugefügt. Da ich Eindeutigkeit in der Spalte SamAccountName
Da ich aber mehrere NULLs zulassen möchte, habe ich eine materialisierte Spalte und keine materialisierte 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 einfach etwas in die berechnete Spalte eingeben, das garantiert eindeutig für die gesamte Tabelle ist, wenn die eigentlich gewünschte eindeutige Spalte NULL ist. In diesem Fall, PartyID
ist eine Identitätsspalte und wird, da sie numerisch ist, niemals mit einer SamAccountName
also hat es bei mir funktioniert. Sie können Ihre eigene Methode ausprobieren - stellen Sie sicher, dass Sie den Bereich Ihrer Daten verstehen, damit es keine Überschneidungen mit echten Daten gibt. Das könnte so einfach sein wie das Voranstellen eines Unterscheidungszeichens wie dieses:
Coalesce('n' + SamAccountName, 'p' + Convert(varchar(11), PartyID))
Auch wenn PartyID
wurde eines Tages nicht mehr numerisch und könnte mit einer SamAccountName
Jetzt ist es egal.
Beachten Sie, dass das Vorhandensein eines Indexes, der die berechnete Spalte enthält, implizit dazu führt, dass jedes Ausdrucksergebnis zusammen mit den anderen Daten in der Tabelle auf der Festplatte gespeichert wird, was zusätzlichen Speicherplatz benötigt.
Beachten Sie, dass Sie, wenn Sie keinen Index wollen, immer noch CPU sparen können, indem Sie den Ausdruck auf der Festplatte vorberechnen lassen, indem Sie das Schlüsselwort PERSISTED
an das Ende der Definition des Spaltenausdrucks.
In SQL Server 2008 und höher sollten Sie auf jeden Fall die gefilterte Lösung verwenden, wenn es möglich ist!
Kontroverse
Bitte beachten Sie, dass einige Datenbankspezialisten dies als einen Fall von "Surrogat-NULLs" ansehen werden, was definitiv Probleme mit sich bringt (hauptsächlich aufgrund von Problemen bei dem Versuch, zu bestimmen, wann etwas ein tatsächlicher Wert oder eine Ersatzwert für fehlende Daten Es kann auch zu Problemen mit der Anzahl der Nicht-NULL-Surrogatwerte kommen, die sich wie verrückt vermehren).
Ich glaube jedoch, dass dieser Fall anders gelagert ist. Die berechnete Spalte, die ich hinzufüge, wird nie dazu verwendet, etwas zu bestimmen. Sie hat keine eigene Bedeutung und kodiert keine Informationen, die nicht bereits separat in anderen, korrekt definierten Spalten zu finden sind. Sie sollte niemals ausgewählt oder verwendet werden.
Meine Geschichte ist also, dass dies kein Ersatz für NULL ist, und ich bleibe dabei! Da wir den Nicht-NULL-Wert eigentlich für keinen anderen Zweck brauchen, als um die UNIQUE
Index zu verwenden, um NULLs zu ignorieren, hat unser Anwendungsfall keines der Probleme, die bei der normalen NULL-Surrogaterstellung auftreten.
All das gesagt, ich habe kein Problem mit der Verwendung einer indizierten Ansicht stattdessen-aber es bringt einige Probleme mit ihm wie 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 den View löschen oder den View so ändern, dass er nicht schemagebunden ist). Siehe die vollständige (lange) Liste der Anforderungen für die Erstellung einer indizierten Ansicht in SQL Server (2005) (auch spätere Versionen), (2000) .
更新情報
Wenn Ihre Spalte numerisch ist, kann es eine Herausforderung sein, sicherzustellen, dass die eindeutige Einschränkung mit Coalesce
führt nicht zu Kollisionen. In diesem Fall gibt es einige Möglichkeiten. Eine könnte darin bestehen, eine negative Zahl zu verwenden, die "Ersatz-NULLs" nur in den negativen Bereich und die "echten Werte" nur in den positiven Bereich zu legen. Alternativ könnte auch das folgende Muster verwendet werden. In der Tabelle Issue
(wobei IssueID
ist die PRIMARY KEY
), kann es sein, dass es eine 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 das Ticket 123 hat, wird die UNIQUE
Einschränkung auf die Werte (123, NULL) sein. Wenn IssueID 2 kein Ticket hat, gilt sie für (NULL, 2). Ein wenig Nachdenken wird zeigen, dass diese Einschränkung für keine Zeile in der Tabelle dupliziert werden kann und trotzdem mehrere NULLs erlaubt.