Eindeutiger Index mit Nullwerten

24. November 2013

Situation in Microsoft Access

Bei dem Beispiel sieht man mal wieder, wie praxisnah viele Funktionen in Access angelegt sind: Oft gibt es die Anforderung, dass in einer Tabelle in einer bestimmten Spalte Nullwerte erlaubt sind und gleichzeitig die Einträge in den Nicht-Nullwerten nicht doppelt vorkommen dürfen. Um dieses zu gewährleisten, kann man in Access bei der Definition eines Indexes die Option Nullwerte ignorieren wählen. Der untenstehende ScreenShot zeigt die Optionsmöglichkeit im Tabellendesigner von Access.

Screenshot des Tabellendesigners in Access

Auf dem SQL-Server ist es etwas komplizierter

Diese Möglichkeit gibt es zumindest vor der Version 2008 auf dem SQL-Server nicht: Aus dessen Sicht stellen die Tabellenzeilen ohne Einträge, also die Nullwerte, in jedem Fall doppelte Einträge dar, so dass einem nichts anderes übrig bleibt, als zunächst einmal einen Index zu definieren, der doppelte Werte zulässt.

Um mehrfache Nicht-Nullwerte in der entsprechenden Tabellenspalte zu verhindern, muss also ein anderes Mittel gefunden werden. Wir verwenden zu diesem Zweck Trigger.

Im untenstehenden Fall haben wir eine Replikation einer Adressdatenbank mit einem Exchange-Server implementiert und speichern in der Datenbank die Entry-IDs der entsprechenden Kontakte auf dem Exchange-Server. Da aber nicht alle Ansprechpartner auch im Exchange Adressbuch stehen, gibt es diverse Einträge mit Nullwerte in der zugehörigen Tabellenspalte. Trotzdem soll die Datenbank aber darüber wachen, dass jede Entry-ID des Exchange-Servers nur einem Datensatz in unserer Datenbank zugeordnet werden darf.

ALTER Trigger [dbo].[Adressen_Ansprechpartner_INSERT_UPDATE] 
  ON [dbo].[Adressen_Ansprechpartner] FOR INSERT, UPDATE 
AS
  IF EXISTS 
    (SELECT t1.AdrAns_ID 
     FROM Inserted AS I 
       JOIN Adressen_Ansprechpartner AS t1 
         ON I.EntryID = t1.EntryID AND I.AdrAns_ID <> t1.AdrAns_ID) 
    BEGIN 
      ROLLBACK TRAN 
      RAISERROR('Keine doppelten Einträge für das Feld EntryID in der Tabelle 
        Adressen_Ansprechpartner zulässig',16,1) 
    END 

  :
  :
  :

Gefilterter Index ab dem SQL-Server 2008

Ab dem SQL-Server 2008 gibt es noch eine weitere Möglichkeit: Den sogenannten gefilterten Index. Dieser kann mit der folgenden Anweisung definiert werden:

CREATE UNIQUE NONCLUSTERED INDEX <Index_Name>
ON <Tabelle>(<Felder>)
WHERE <Feld> IS NOT NULL;

Dieser Index wird zuverlässig darüber wachen, dass keine doppelten Werte in der entsprechenden Spalte vorkommen. Es bleibt darüber hinaus zu hoffen, dass der Optimierer bei einer Abfrage erkennt, das dieser Index auch zur Beschleunigung von Abfragen verwendet wird. Um dieses zweifelsfrei festzustellen, kann die SHOWPLAN-Direktive verwendet werden. Oder man zwingt den SQL-Server direkt, den angelegten Index zu verwenden. Das geht folgendermaßen:

SELECT <Felder> 
FROM <Tabelle> 
WITH ( INDEX ( <Index_Name> ) ) 
WHERE <Feld> IS NOT NULL And <weitere Bedingungen>;

Es bleibt noch nachzutragen, dass das SQL Server Management Studio auf obige Art und Weise erzeugte Indizes zwar anzeigt, aber nicht deren Besonderheit erkennt. Es ist, wie ich erst später festgestellt habe, sogar noch schlimmer. Ändert man die Struktur einer Tabelle so, dass sie komplett neu erzeugt werden muss, so versucht das SQL Server Management Studio den Index als ganz normalen eindeutigen Index zu erzeugen, was natürlich zu einem Fehler führt. Man muss den Index also zunächst löschen, dann die Änderung in der Datenstruktur vornehmen und danach den Index neu erzeugen. Das ist echt abgefahren...

Kommentare

Neuen Kommentar schreiben

Hinweis: Name und Kommentar werden gespeichert und auf der Website angezeigt. Die E-Mail-Adresse wird nicht veröffentlicht. Sie dient nur dazu, ggf. eine Frage zu beantworten, und wird anschließend gelöscht. Für weitere Infos lesen Sie bitte unsere » Datenschutzerklärung.