Chcę mieć unikalne ograniczenie w kolumnie, którą zamierzam wypełnić GUID. Jednak moje dane zawierają wartości null dla tych kolumn. Jak utworzyć ograniczenie, które zezwala na wiele wartości null?
Oto przykładowy scenariusz . Rozważ ten schemat:
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)
)
Następnie zobacz ten kod dla tego, co próbuję osiągnąć:
-- 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);
Końcowa instrukcja kończy się niepowodzeniem i pojawia się komunikat:
Naruszenie ograniczenia UNIKALNEGO KLUCZA „UQ_People_LibraryCardId”. Nie można wstawić duplikatu klucza w obiekcie „dbo.People”.
Jak mogę zmienić mój schemat i / lub ograniczenie unikatowości, aby zezwalało na wiele NULL
wartości, jednocześnie sprawdzając unikalność na rzeczywistych danych?
sql-server
tsql
Stuart
źródło
źródło
null
nie jest to wartość, ale brak wartości. Zgodnie ze standardem SQLnull
nie jest uważany za równynull
. Dlaczego więc wielokrotnośćnull
powinna być naruszeniem wyjątkowości?Odpowiedzi:
SQL Server 2008 +
Możesz utworzyć unikalny indeks, który akceptuje wiele wartości NULL z
WHERE
klauzulą. Zobacz odpowiedź poniżej .Przed SQL Server 2008
Nie można utworzyć ograniczenia UNIKALNEGO i zezwolić na wartości NULL. Musisz ustawić wartość domyślną NEWID ().
Zaktualizuj istniejące wartości do NEWID (), gdzie NULL, przed utworzeniem ograniczenia UNIQUE.
źródło
To, czego szukasz, jest rzeczywiście częścią standardów ANSI SQL: 92, SQL: 1999 i SQL: 2003, tzn. Ograniczenie UNIKALNE musi uniemożliwiać powielanie wartości innych niż NULL, ale akceptować wiele wartości NULL.
Jednak w świecie SQL Server firmy Microsoft dozwolona jest jedna wartość NULL, ale wiele wartości NULL nie jest ...
W SQL Server 2008 można zdefiniować unikalny filtrowany indeks na podstawie predykatu, który wyklucza wartości NULL:
We wcześniejszych wersjach można zastosować WIDOKI z predykatem NOT NULL, aby wymusić ograniczenie.
źródło
SQL Server 2008 i nowsze wersje
Po prostu odfiltruj unikalny indeks:
W niższych wersjach widok zmaterializowany nadal nie jest wymagany
W przypadku SQL Server 2005 i wcześniejszych można to zrobić bez widoku. Właśnie dodałem unikalne ograniczenie, tak jakbyś prosił o jeden z moich stolików. Biorąc pod uwagę, że chcę wyjątkowość w kolumnie
SamAccountName
, ale chcę pozwolić na wiele wartości NULL, użyłem zmaterializowanej kolumny zamiast zmaterializowanego widoku:Musisz po prostu umieścić w kolumnie obliczeniowej coś, co będzie gwarantowane jako unikalne w całej tabeli, gdy rzeczywista pożądana unikalna kolumna ma wartość NULL. W tym przypadku
PartyID
jest kolumna tożsamości, a numeryczne nigdy nie pasuje do żadnejSamAccountName
, więc zadziałało dla mnie. Możesz wypróbować własną metodę - upewnij się, że rozumiesz domenę swoich danych, aby nie było możliwości krzyżowania się z rzeczywistymi danymi. Może to być tak proste, jak przygotowanie znaku wyróżniającego, takiego jak ten:Nawet jeśli
PartyID
kiedyś stanie się nieliczbowy i może się pokrywać zSamAccountName
, teraz nie będzie to miało znaczenia.Zauważ, że obecność indeksu zawierającego kolumnę obliczoną domyślnie powoduje zapisanie każdego wyniku wyrażenia na dysku z innymi danymi w tabeli, co NIE wymaga dodatkowego miejsca na dysku.
Zauważ, że jeśli nie chcesz indeksu, możesz nadal oszczędzać CPU, ustawiając wyrażenie na dysk, dodając słowo kluczowe
PERSISTED
na końcu definicji wyrażenia kolumny.W SQL Server 2008 i nowszych wersjach zdecydowanie użyj filtrowanego rozwiązania, jeśli to możliwe!
Spór
Należy pamiętać, że niektórzy specjaliści od baz danych uznają to za przypadek „zastępczych wartości NULL”, które zdecydowanie mają problemy (głównie z powodu problemów z ustaleniem, kiedy coś jest rzeczywistą wartością lub wartością zastępczą dla brakujących danych ; mogą też występować problemy z liczbą mnogich wartości zastępczych innych niż NULL mnożącymi się jak szalone).
Uważam jednak, że ta sprawa jest inna. Dodana kolumna obliczeniowa nigdy nie zostanie wykorzystana do ustalenia czegokolwiek. Nie ma ono żadnego znaczenia i nie koduje żadnych informacji, które nie zostały jeszcze znalezione osobno w innych, poprawnie zdefiniowanych kolumnach. Nigdy nie należy go wybierać ani używać.
Tak więc, moja historia jest taka, że to nie jest zastępcza wartość NULL i trzymam się tego! Ponieważ tak naprawdę nie chcemy wartości innej niż NULL w jakimkolwiek celu innym niż nakłonienie
UNIQUE
indeksu do zignorowania wartości NULL, w naszym przypadku użycia nie ma żadnych problemów, które pojawiają się podczas normalnego tworzenia zastępczej wartości NULL.To powiedziawszy, zamiast tego nie mam problemu z użyciem widoku indeksowanego, ale wiąże się to z pewnymi problemami, takimi jak wymóg użycia
SCHEMABINDING
. Baw się dobrze, dodając nową kolumnę do tabeli podstawowej (musisz przynajmniej upuścić indeks, a następnie upuścić widok lub zmienić widok, aby nie był powiązany ze schematem). Zobacz pełną (długą) listę wymagań dotyczących tworzenia indeksowanego widoku w SQL Server (2005) (także późniejsze wersje), (2000) .Aktualizacja
Jeśli twoja kolumna jest liczbowa, może istnieć wyzwanie, aby upewnić się, że użycie unikalnego ograniczenia
Coalesce
nie spowoduje kolizji. W takim przypadku istnieje kilka opcji. Można użyć liczby ujemnej, aby „zastępować wartości NULL” tylko w zakresie ujemnym, a „wartości rzeczywiste” tylko w zakresie dodatnim. Alternatywnie można zastosować następujący wzór. W tabeliIssue
(gdzieIssueID
jestPRIMARY KEY
) może istniećTicketID
, ale nie musi , ale jeśli istnieje, musi być unikalna.Jeśli IssueID 1 ma bilet 123,
UNIQUE
ograniczenie będzie dotyczyło wartości (123, NULL). Jeśli IssueID 2 nie ma biletu, będzie włączony (NULL, 2). Pewna myśl pokaże, że tego ograniczenia nie można powielić dla żadnego wiersza w tabeli i nadal dopuszcza wiele wartości NULL.źródło
W przypadku osób korzystających z programu Microsoft SQL Server Manager i chcących utworzyć indeks Unique, ale dopuszczający wartość Nullable, możesz utworzyć swój unikalny indeks, tak jak to zwykle bywało we właściwościach indeksu dla nowego indeksu, wybierz „Filtr” z lewego panelu, a następnie wpisz twój filtr (który jest twoją klauzulą where). Powinien przeczytać coś takiego:
Działa to z MSSQL 2012
źródło
Kiedy zastosowałem poniższy unikalny indeks:
każda aktualizacja o wartości innej niż zero i wstawianie nie powiodło się z powodu błędu poniżej:
Znalazłem to na MSDN
Więc żeby to działało poprawnie, zrobiłem to
Wierzę, że można ustawić tę opcję w kodzie za pomocą
ale nie przetestowałem tego
źródło
Utwórz widok, który wybiera tylko nie-
NULL
kolumny i utwórzUNIQUE INDEX
widok:Pamiętaj, że musisz wykonać
INSERT
iUPDATE
' na widoku zamiast tabeli.Możesz to zrobić za pomocą
INSTEAD OF
wyzwalacza:źródło
Można to zrobić również u projektanta
Kliknij prawym przyciskiem myszy Indeks> Właściwości, aby wyświetlić to okno
źródło
Możliwe jest utworzenie unikalnego ograniczenia dla widoku indeksowanego klastrowanego
Możesz utworzyć widok w następujący sposób:
i wyjątkowe ograniczenie takie jak to:
źródło
Może rozważyć „
INSTEAD OF
” wyzwalacz i samemu sprawdzić? Z nieklastrowanym (nieunikalnym) indeksem w kolumnie, aby umożliwić wyszukiwanie.źródło
Jak wspomniano wcześniej, SQL Server nie implementuje standardu ANSI, jeśli chodzi o
UNIQUE CONSTRAINT
. Jest na to bilet w Microsoft Connect od 2007 roku. Jak sugerowano tutaj i tutaj, najlepsze opcje na dziś to użycie filtrowanego indeksu, jak podano w innej odpowiedzi lub kolumnie obliczeniowej, np .:źródło
Możesz utworzyć wyzwalacz INSTEAD OF w celu sprawdzenia określonych warunków i błędu, jeśli są one spełnione. Tworzenie indeksu może być kosztowne w przypadku większych tabel.
Oto przykład:
źródło
Nie możesz tego zrobić z
UNIQUE
ograniczeniem, ale możesz to zrobić za pomocą wyzwalacza.źródło
źródło
kod ten, jeśli utworzysz formularz rejestracyjny w textBox i użyjesz insert, a ur textBox jest pusty i klikniesz przycisk Prześlij.
źródło