Unikatowy indeks zezwalający na NULLe

Unikatowość w indeksie

Jak dobrze wiemy, czy to indeks nieklastrowy czy klastrowy (skupiamy się na indeksach “rowstore”) może zostać opatrzony opcjonalną klauzulą UNIQUE która definiuje go jako unikatowy, czyli nie posiadający duplikatów w kolumnach tworzących jego definicję (jednak duplikaty spokojnie mogą się znajdować wśród kolumn zawartych w klauzuli INCLUDE).

Przygotujmy sobie tabelę z takim indeksem i wypełnijmy ją poprawnymi danymi:

DROP TABLE IF EXISTS dbo.testDuplicates;
CREATE TABLE dbo.testDuplicates ([Id] INT NOT NULL IDENTITY(1,1) CONSTRAINT [PK_DupeId] PRIMARY KEY,
							  [Value] NVARCHAR(50) NULL,
							  INDEX [IX_UQ_NC_loneliness] UNIQUE NONCLUSTERED ([Value]));
INSERT INTO dbo.testDuplicates([Value])
VALUES
	('a'),
	('b'),
	('c'),
	('d'),
	('e');

Powyższy kod stworzy nam tabelę z unikatowym indeksem na kolumnie Value. Spróbujmy teraz dorzucić tam wiersz ze zduplikowaną wartości i zobaczmy co się stanie.

INSERT INTO dbo.testDuplicates([Value]) VALUES ('c')

Woah, jaki piękny błąd!

Msg 2601, Level 14, State 1, Line 1
Cannot insert duplicate key row in object 'dbo.testDuplicates' with unique index 'IX_UQ_NC_loneliness'. The duplicate key value is (c).

I wszystko fajnie, jesteśmy uratowani! Jednak zostaje pytanie, co zrobi SQL Server z wartością NULL? Czy potraktuje ją specjalnie i pominie sprawdzenie unikatowości przy wrzucaniu więcej niż jednego wiersza? Pozwoli wrzucić tylko jeden wiersz? A może w ogóle nie pozwoli na NULLe? Sprawdźmy to!

INSERT INTO dbo.testDuplicates([Value]) VALUES (NULL);
INSERT INTO dbo.testDuplicates([Value]) VALUES (NULL);

Podzieliłem to na dwa inserty aby sprawdzić który z nich się wywróci. I co się zadziało?

(1 row affected)
Msg 2601, Level 14, State 1, Line 2
Cannot insert duplicate key row in object 'dbo.testDuplicates' with unique index 'IX_UQ_NC_loneliness'. The duplicate key value is (<NULL>).

Pierwsze zapytanie wykonało się poprawnie (o czym świadczy komunikat “1 row affected“), jednak drugie już rzuciło nam przykrym błędem duplikatu wartości. Peszkie.

Co robić, jak żyć?

Przyjmijmy jednak, że z jednej strony potrzebujemy zachować unikatowość wartości, które mają znaczenie, a jednocześnie użytkownicy mają być w stanie umieścić tam tyle wartości NULL ile tylko sobie wymyślą. Jest na to pewien sposób i nazywa się “indeks filtrowany”. Dokładnie tak jak w zwykłym zapytaniu SELECT mamy klauzulę WHERE, tak samo może ona występować w obrębie tworzenia indeksu. Spójrzcie.

--Najpierw usuwamy istniejący indeks
DROP INDEX [IX_UQ_NC_loneliness] ON dbo.testDuplicates;
GO
--I zakładamy nowy, zwróćcie uwagę na klauzulę WHERE na końcu definicji
CREATE UNIQUE NONCLUSTERED INDEX [IX_UQ_NC_emptiness] ON dbo.testDuplicates([Value]) WHERE [Value] IS NOT NULL;
GO

Więc stworzyliśmy nowy indeks i powiedzieliśmy SQL Serverowi żeby utrzymywał go tylko dla wartości które nie są NULL. Jak to działa? Puśćmy ponownie zapytanie z wrzucaniem nieznanych wartości.

INSERT INTO dbo.testDuplicates([Value]) VALUES (NULL);
INSERT INTO dbo.testDuplicates([Value]) VALUES (NULL);

Tada! Oba zapytania wykonały się poprawnie, a wartości NULL zostały umieszczone w kolejnych wierszach tabeli. A co jakbyśmy chcieli umieścić prawdziwy duplikat?

INSERT INTO dbo.testDuplicates([Value]) VALUES ('a');

Msg 2601, Level 14, State 1, Line 1
Cannot insert duplicate key row in object 'dbo.testDuplicates' with unique index 'IX_UQ_NC_emptiness'. The duplicate key value is (a).

No nie da się.

Oki, to pa!

Zobacz także:

  • Piotr Szymański

    Kategoria:

    Hejka! Zapraszam na skrót z minionych dwóch tygodni, który przyswoić możecie przy ciepłej herbatce w te mroczne, szare dni. W opublikowanym przez Google 14 listopada ostrzeżeniu wskazano kilka najważniejszych rodzajów oszustw internetowych. Uwagę zwrócono między na niebezpieczne techniki ataków typu cloaking, które nabierają nowego wymiaru dzięki wykorzystaniu sztucznej inteligencji. Cloaking polega na ukrywaniu przed użytkownikiem […]
  • Piotr Szymański

    Kategoria:

    Hejka po dłuższej przerwie! Zaczynamy świeżym tematem. Raptem kilkanaście godzin temu do użytkowników trafiła, zapowiedziana 25 lipca, funkcja SearchGPT od OpenAI, umożliwiająca, w przeciwieństwie do tradycyjnych modeli językowych, na integrację z internetem w czasie rzeczywistym. SearchGPT ma dostęp do aktualnych informacji z sieci, co pozwala na udzielanie odpowiedzi opartych na najnowszych danych. Ponadto SearchGPT dostarcza […]
  • Piotr Szymański

    Kategoria:

    Hejson! Dzisiejsza konsumpcja mediów ma to do siebie, że odbywa się na 5-6 calowym ekranie telefonu. Ma też to do siebie, że zanim zdjęcie dotrze do Ciebie, to przejdzie przez 6 konwersacji na jedynym słusznym messengerze, zatem zostanie 6-cio krotnie skompresowane. W międzyczasie, jak będziecie mieli pecha, to jakiś wujek zrobi screena, zamiast zapisać zdjęcie […]
  • Piotr Szymański

    Kategoria:

    Hej! Robimy bardzo dużo zdjęć, a co za tym idzie – wiele z nich jest niechlujnych, z zabałagnionym tłem. Możemy jednak chcieć wykorzystać je do pochwalenia się naszym ryjkiem na jakimś publicznym profilu, gdyż np. naturalne, miękkie światło korzystnie eksponuje naszą facjatę. Podejścia mogą być dwa – albo zdecydujemy się na blur bądź zupełne usunięcie […]
  • Piotr Szymański

    Kategoria:

    Strzałeczka. Nvidia przejęła OctoAI, startup specjalizujący się w optymalizacji modeli uczenia maszynowego. To już piąta akwizycja Nvidii w 2024 roku, co czyni aktualnie nam panujący rok rekordowym pod względem liczby przejęć. OctoAI, założone w 2019 roku przez Luisa Ceze, skupiło się na tworzeniu oprogramowania zwiększającego wydajność modeli uczenia maszynowego na różnych platformach sprzętowych. Oprogramowanie OctoAI […]