Ich möchte eine eindeutige Einschränkung für eine Spalte haben, die ich mit GUIDs füllen werde. Meine Daten enthalten jedoch Nullwerte für diese Spalten. Wie erstelle ich die Einschränkung, die mehrere Nullwerte zulässt?
Hier ist ein Beispielszenario . Betrachten Sie dieses Schema:
CREATE TABLE People (
Id INT CONSTRAINT PK_MyTable PRIMARY KEY IDENTITY,
Name NVARCHAR(250) NOT NULL,
LibraryCardId UNIQUEIDENTIFIER NULL,
CONSTRAINT UQ_People_LibraryCardId UNIQUE (LibraryCardId)
)
Dann sehen Sie diesen Code für das, was ich erreichen möchte:
-- This works fine:
INSERT INTO People (Name, LibraryCardId)
VALUES ('John Doe', 'AAAAAAAA-AAAA-AAAA-AAAA-AAAAAAAAAAAA');
-- This also works fine, obviously:
INSERT INTO People (Name, LibraryCardId)
VALUES ('Marie Doe', 'BBBBBBBB-BBBB-BBBB-BBBB-BBBBBBBBBBBB');
-- This would *correctly* fail:
--INSERT INTO People (Name, LibraryCardId)
--VALUES ('John Doe the Second', 'AAAAAAAA-AAAA-AAAA-AAAA-AAAAAAAAAAAA');
-- This works fine this one first time:
INSERT INTO People (Name, LibraryCardId)
VALUES ('Richard Roe', NULL);
-- THE PROBLEM: This fails even though I'd like to be able to do this:
INSERT INTO People (Name, LibraryCardId)
VALUES ('Marcus Roe', NULL);
Die endgültige Anweisung schlägt mit einer Meldung fehl:
Verletzung der UNIQUE KEY-Einschränkung 'UQ_People_LibraryCardId'. Doppelter Schlüssel kann nicht in Objekt 'dbo.People' eingefügt werden.
Wie kann ich mein Schema und / oder meine Eindeutigkeitsbeschränkung so ändern, dass mehrere NULL
Werte zulässig sind, während die Eindeutigkeit der tatsächlichen Daten überprüft wird?
sql-server
tsql
Stuart
quelle
quelle
null
kein Wert ist, sondern das Fehlen von Wert. Wird nach dem SQL-Standardnull
nicht als gleich angesehennull
. Warumnull
sollte Multiple also eine Verletzung der Eindeutigkeit sein?Antworten:
SQL Server 2008 +
Sie können einen eindeutigen Index erstellen, der mehrere NULL-Werte mit einer
WHERE
Klausel akzeptiert . Siehe die Antwort unten .Vor SQL Server 2008
Sie können keine EINZIGARTIGE Einschränkung erstellen und NULL-Werte zulassen. Sie müssen den Standardwert NEWID () festlegen.
Aktualisieren Sie die vorhandenen Werte auf NEWID (), wobei NULL ist, bevor Sie die UNIQUE-Einschränkung erstellen.
quelle
Was Sie suchen, ist in der Tat Teil der ANSI-Standards SQL: 92, SQL: 1999 und SQL: 2003, dh eine UNIQUE-Einschränkung muss doppelte Nicht-NULL-Werte nicht zulassen, aber mehrere NULL-Werte akzeptieren.
In der Microsoft-Welt von SQL Server ist jedoch ein einzelner NULL-Wert zulässig, mehrere NULL-Werte jedoch nicht ...
In SQL Server 2008 können Sie einen eindeutigen gefilterten Index basierend auf einem Prädikat definieren, das NULL-Werte ausschließt:
In früheren Versionen können Sie mit einem NOT NULL-Prädikat auf VIEWS zurückgreifen, um die Einschränkung zu erzwingen.
quelle
SQL Server 2008 und höher
Filtern Sie einfach einen eindeutigen Index:
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: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. DaherSamAccountName
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:Selbst wenn es
PartyID
eines Tages nicht numerisch wurde und mit einem zusammenfallen könnteSamAccountName
, 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 TabelleIssue
(woIssueID
ist diePRIMARY KEY
) kann es eine geben oder nichtTicketID
, aber wenn es eine gibt, muss sie eindeutig sein.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.quelle
Für Benutzer , die Microsoft SQL Server Manager verwenden und einen eindeutigen, aber nullfähigen Index erstellen möchten, können Sie Ihren eindeutigen Index wie gewohnt in Ihren Indexeigenschaften für Ihren neuen Index erstellen. Wählen Sie im linken Bereich "Filter" aus und geben Sie ein Ihr Filter (das ist Ihre where-Klausel). Es sollte ungefähr so lauten:
Dies funktioniert mit MSSQL 2012
quelle
Als ich den folgenden eindeutigen Index angewendet habe:
Jedes Nicht-Null-Update und Einfügen schlug mit dem folgenden Fehler fehl:
Ich habe das auf MSDN gefunden
Damit dies richtig funktioniert, habe ich das getan
Ich glaube, es ist möglich, diese Option im Code mit zu setzen
aber ich habe das nicht getestet
quelle
Erstellen Sie eine Ansicht, in der nur Nicht-
NULL
Spalten ausgewählt werden, und erstellen Sie FolgendesUNIQUE INDEX
in der Ansicht:Beachten Sie, dass Sie anstelle der Tabelle
INSERT
'undUPDATE
' in der Ansicht ausführen müssen .Sie können es mit einem
INSTEAD OF
Auslöser tun :quelle
Dies kann auch im Designer erfolgen
Klicken Sie mit der rechten Maustaste auf Index> Eigenschaften , um dieses Fenster aufzurufen
quelle
Es ist möglich, eine eindeutige Einschränkung für eine gruppierte indizierte Ansicht zu erstellen
Sie können die Ansicht folgendermaßen erstellen:
und die einzigartige Einschränkung wie folgt:
quelle
Vielleicht einen "
INSTEAD OF
" Auslöser in Betracht ziehen und die Prüfung selbst durchführen? Mit einem nicht gruppierten (nicht eindeutigen) Index für die Spalte, um die Suche zu ermöglichen.quelle
Wie bereits erwähnt, implementiert SQL Server den ANSI-Standard nicht, wenn es darum geht
UNIQUE CONSTRAINT
. Dafür gibt es seit 2007 ein Ticket für Microsoft Connect . Wie dort und hier vorgeschlagen, besteht die beste Option ab heute darin, einen gefilterten Index zu verwenden, wie in einer anderen Antwort oder einer berechneten Spalte angegeben, z.quelle
Sie können STATT erstellen Trigger , um nach bestimmten Bedingungen und Fehlern zu suchen, wenn diese erfüllt sind. Das Erstellen eines Index kann für größere Tabellen kostspielig sein.
Hier ist ein Beispiel:
quelle
Sie können dies nicht mit einer
UNIQUE
Einschränkung tun , aber Sie können dies in einem Trigger tun.quelle
quelle
Dieser Code, wenn Sie ein Registerformular mit textBox erstellen und einfügen verwenden und Ihre textBox leer ist und Sie auf die Schaltfläche "Senden" klicken.
quelle