Wie kann ich mehrere Spalten beschränken, um Duplikate zu verhindern, aber Nullwerte ignorieren?

8

Hier ist ein kleines Experiment, das ich in einer Oracle-Datenbank (10g) ausgeführt habe. Abgesehen von (Oracles) Implementierungskomfort kann ich nicht herausfinden, warum einige Einfügungen akzeptiert und andere zurückgewiesen werden.

%Vor%

Unter der Annahme, dass es sinnvoll ist, gelegentlich Zeilen mit einigen Spaltenwerten zu haben, die unbekannt sind, kann ich an zwei mögliche Anwendungsfälle denken, bei denen Duplikate vermieden werden:
 1. Ich möchte Duplikate ablehnen, aber akzeptieren, wenn der Wert einer eingeschränkten Spalte unbekannt ist.
 2. Ich möchte Duplikate ablehnen, auch wenn der Wert einer eingeschränkten Spalte unbekannt ist.

Anscheinend implementiert Oracle etwas anderes:
 3. Ablehnen von Duplikaten, aber akzeptieren (nur) wenn alle eingeschränkten Spaltenwerte unbekannt sind.

Ich kann mir überlegen, wie ich die Implementierung von Oracle nutzen kann, um case (2) zu verwenden, zum Beispiel einen speziellen Wert für "unknown" zu haben und die Spalten nicht nullbar zu machen. Aber ich kann nicht herausfinden, wie man Fall (1) verwendet.

Mit anderen Worten, wie kann ich Oracle dazu bringen, so zu handeln?

%Vor%     
Chris 23.03.2009, 22:00
quelle

4 Antworten

7
%Vor%

Ein funktionaler Index! Im Grunde musste ich nur sicherstellen, dass alle Tupel, die ich ignorieren möchte (dh akzeptieren), in alle Nullen übersetzt werden. Hässlich, aber nicht hässlich. Funktioniert wie gewünscht.

Ich habe es mit Hilfe einer Lösung für eine andere Frage herausgefunden: Wie schränkt man eine Datenbanktabelle so ein, dass nur eine Zeile einen bestimmten Wert in einer Spalte haben kann?

Also geh und gib Tony Andrews Punkte. :)

    
Chris 23.05.2017, 12:19
quelle
7

Probieren Sie einen funktionsbasierten Index aus:

Erstelle einen eindeutigen Index sandbox_idx in der Sandbox (CASE WENN a NULL DANN NULL WENN b NULL IST, dann NULL ELSE a || ', || b ENDE);

Es gibt andere Möglichkeiten, diese Katze zu häuten, aber das ist einer von ihnen.

    
DCookie 23.03.2009 22:28
quelle
2

Ich bin kein Oracle-Typ, aber hier ist eine Idee, die funktionieren sollte, wenn Sie eine berechnete Spalte in einen Index in Oracle einfügen können.

Fügen Sie Ihrer Tabelle (und Ihrem UNIQUE-Index) eine zusätzliche Spalte hinzu, die wie folgt berechnet wird: Sie ist NULL, wenn a und b nicht NULL sind und andernfalls der Primärschlüssel der Tabelle. Ich nenne diese zusätzliche Spalte "Nullbuster" aus offensichtlichen Gründen.

%Vor%

Ich habe dieses Beispiel ungefähr 2002 in der Usenet-Gruppe microsoft.public.sqlserver.programming angegeben. Sie finden die Diskussionen, wenn Sie groups.google.com nach dem Wort "nullbuster" durchsuchen. Die Tatsache, dass Sie Oracle verwenden, sollte nicht viel ausmachen.

P.S. In SQL Server wird diese Lösung durch gefilterte Indizes ersetzt:

%Vor%

Der Thread, auf den Sie verwiesen haben, deutet darauf hin, dass Oracle Ihnen diese Option nicht bietet. Hat es auch nicht die Möglichkeit einer indizierten Sicht, was eine andere Alternative ist?

%Vor%     
Steve Kass 10.08.2009 02:34
quelle
1

Ich denke du kannst das dann.

Nur für den Datensatz, aber ich lasse meinen Absatz zu erklären, warum Oracle verhält sich so, wenn Sie einen einfachen eindeutigen Index für zwei Spalten haben:

Oracle akzeptiert niemals zwei (1, null) -Paare, wenn die Spalten eindeutig indiziert sind.

Ein Paar von 1 und einer Null wird als "indexierbares" Paar betrachtet. Ein Paar von zwei Nullen kann nicht indiziert werden. Deshalb können Sie beliebig viele Null-Paare einfügen.

(1, null) wird indiziert, weil 1 indiziert werden kann. Wenn Sie das nächste Mal versuchen, (1, null) einzufügen, wird 1 vom Index übernommen und die eindeutige Einschränkung wird verletzt.

(null, null) wird nicht indiziert, da kein zu indizierender Wert vorhanden ist. Deshalb verletzt es nicht die eindeutige Einschränkung.

    
Petros 23.03.2009 22:38
quelle