Einführung in SQL: WHERE-Klausel im Detail
Aus Wikibooks
In diesem Kapitel werden die Einzelheiten der WHERE-Klausel genauer behandelt. Diese Angaben sind vor allem für den SELECT-Befehl, aber auch für UPDATE und DELETE von Bedeutung.
Die Beispiele beziehen sich auf den Anfangsbestand der Beispieldatenbank; auf die Ausgabe der selektierten Datensätze verzichte ich. Bitte probieren Sie alle Beispiele aus und nehmen Sie verschiedene Änderungen vor, um die Auswirkungen zu erkennen.
Inhaltsverzeichnis |
[Bearbeiten] Allgemeine Hinweise
Die WHERE-Klausel ist (neben der Verknüpfung mehrerer Tabellen) der wichtigste Bestandteil des SELECT-Befehls: Je sorgfältiger die Auswahlbedingungen formuliert werden, desto genauer ist das Ergebnis der Abfrage.
Neben den hier erläuterten Varianten bietet jedes DBMS noch andere, z.B. STARTING WITH oder SIMILAR.
Anstelle konstanter Werte können auch passende Ausdrücke angegeben werden, z.B. Funktionen oder Unterabfragen.
Verwenden Sie bei den Beispielen möglichst immer auch die Umkehrung der Auswahl mit bzw. ohne NOT. Wie in Ausführliche SELECT-Struktur zur WHERE-Klausel angegeben, steht das NOT ggf. unmittelbar vor dem Parameter-Namen.
[Bearbeiten] Eine einzelne Bedingung
[Bearbeiten] Größenvergleich zweier Werte
Der einfachste Weg ist der direkte Vergleich zweier Werte, nämlich der Inhalt einer Spalte mit einem konstanten Wert. Dies ist möglich mit den folgenden Vergleichsoperatoren, und zwar für alle Datentypen, die verglichen werden können – Zahlen, Zeichenketten, Datumsangaben.
= < > <= >= <>
Beispiele:
Suche einen Datensatz, bei dem der Wert in der Spalte ID gleich ist zu einem vorgegebenen Wert.
Suche Datensätze, bei denen der Name kleiner als 'B' ist, also mit 'A' anfängt.
Suche Führerschein-Neulinge.
Führerschein-Neulinge
SQL-Quelltext:
SELECT * FROM Versicherungsnehmer WHERE Fuehrerschein >= '01.01.2007';
Suche Fahrzeugtypen mit kurzer Bezeichnung.
Bei diesen Vergleichen ist NOT zwar ebenfalls möglich; besser verständlich ist aber ein anderer passender Operator.
[Bearbeiten] BETWEEN AND – Werte zwischen zwei Grenzen
Mit der Bedingung BETWEEN <wert1> AND <wert2> wird direkt mit einem Bereich verglichen; die Grenzwerte gehören zum Bereich. Auch dies ist möglich für Zahlen, Zeichenketten, Datumsangaben.
Suche Datensätze, bei denen die PLZ außerhalb eines Bereichs 45000...45999 liegt.
[Bearbeiten] LIKE – Ähnlichkeiten (1)
Die LIKE-Bedingung vergleicht Zeichenketten "ungenau": Der gesuchte Text soll als Wert in einer Spalte enthalten sein; dazu werden
Wildcards benutzt: Der Unterstrich '_' steht für ein beliebiges einzelnes Zeichen, das an der betreffenden Stelle vorkommen kann. Das Prozentzeichen '%' steht für eine beliebige Zeichenkette mit 0 oder mehr Zeichen.
Diese Bedingung wird vor allem in zwei Situationen gerne benutzt:
- Der Suchbegriff ist sehr lang; dem Anwender soll es genügen, den Anfang einzugeben.
- Der Suchbegriff ist nicht genau bekannt (z.B. nicht richtig lesbar).
Beispiele:
Der Ortsname beginnt nicht mit 'B'; der Inhalt dahinter ist beliebig.
Der Ortsname enthält irgendwo 'alt' mit beliebigem Inhalt davor und dahinter.
Der Anfangsbuchstabe des Namens ist unklar, aber danach folgen 'ei'.
Ein Problem haben wir, wenn eines der Wildcard-Zeichen Teil des Suchbegriffs sein soll. Dann muss dem LIKE-Parameter mitgeteilt werden, dass '%' bzw. '_' als "echtes" Zeichen zu verstehen ist. Das geschieht dadurch, dass ein spezielles Zeichen davor gesetzt wird und dieses Zeichen als
ESCAPE-Zeichen angegeben wird:
Innerhalb der Beschreibung kommt die Zeichenfolge '10%' vor.
Vergleichen Sie das Abfrageergebnis, wenn der ESCAPE-Parameter weggelassen wird oder wenn eines oder mehrere der Sonderzeichen im LIKE-Parameter fehlen.
[Bearbeiten] CONTAINS u.a. – Ähnlichkeiten (2)
Ein Problem des LIKE-Parameters ist die Verwendung der Wildcard-Zeichen '%' und '_', die man gerne vergisst oder (wie im letzten Beispiel) nicht genau genug beachtet. Deshalb gibt es verschiedene Vereinfachungen.
CONTAINS – in Firebird CONTAINING – prüft, ob eine Zeichenkette im Feldinhalt enthalten ist.
Teil der Beschreibung ist die Zeichenkette '10%'
SQL-Quelltext:
SELECT * FROM Schadensfaelle WHERE Beschreibung CONTAINS '10%';
Bitte prüfen Sie in der Beschreibung Ihres DBMS, welche Möglichkeiten für Suche nach Ähnlichkeiten außerdem angeboten werden.
[Bearbeiten] IS NULL – null-Werte prüfen
Wie schon unter Relationale Datenbanken besprochen, haben NULL-Werte eine besondere Bedeutung. Mit den folgenden beiden Abfragen werden nicht alle Datensätze gefunden:
8 Mitarbeiter mit Mobil-Nummer
SQL-Quelltext:
SELECT ID, Name, Vorname, Mobil FROM Mitarbeiter WHERE Mobil <> '';
10 Mitarbeiter ohne Mobil-Nummer
SQL-Quelltext:
SELECT ID, Name, Vorname, Mobil FROM Mitarbeiter WHERE Mobil = '';
Nanu, es gibt doch 28 Mitarbeiter; wo sind die übrigen geblieben? Für diese Fälle gibt es mit IS NULL eine spezielle Abfrage:
10 Mitarbeiter ohne Angabe
SQL-Quelltext:
SELECT ID, Name, Vorname, Mobil FROM Mitarbeiter WHERE Mobil IS NULL;
Der Vollständigkeit halber weise ich darauf hin, dass die folgende Abfrage tatsächlich die richtige Gegenprobe liefert:
18 Mitarbeiter mit irgendeiner Angabe (auch mit "leerer" Angabe)
SQL-Quelltext:
SELECT ID, Name, Vorname, Mobil FROM Mitarbeiter WHERE Mobil IS NOT NULL;
Die folgende Abfrage liefert überhaupt kein Ergebnis, weil NULL eben kein Wert ist.
Es gibt keine einzelne Bedingung, die alle Datensätze ohne explizite Mobil-Angabe auf einmal angibt. Es gibt nur die Möglichkeit, die beiden Bedingungen "IS NULL" und "ist leer" zu verknüpfen:
20 Mitarbeiter ohne ausdrückliche Angabe
SQL-Quelltext:
SELECT ID, Name, Vorname, Mobil FROM Mitarbeiter WHERE ( Mobil IS NULL ) OR ( Mobil = '' );
Beachten Sie auch bei "WHERE ... IS [NOT] NULL" die Bedeutung von NULL:
- Bei Zeichenketten ist zu unterscheiden zwischen dem "leeren" String und dem NULL-Wert.
- Bei Zahlen ist zu unterscheiden zwischen der Zahl "0" (null) und dem NULL-Wert.
- Bei Datumsangaben ist zu unterscheiden zwischen einem vorhandenen Datum und dem NULL-Wert; ein Datum, das der Zahl 0 entspräche, gibt es nicht. (Man könnte allenfalls das kleinste mögliche Datum wie dem '01.01.0100' benutzen, aber dies ist bereits ein Datum.)
[Bearbeiten] IN – genauer Vergleich mit einer Liste
Der IN-Parameter vergleicht, ob der Inhalt einer Spalte in der angegebenen Liste enthalten ist. Die Liste kann mit beliebigen Datentypen arbeiten.
Hole die Liste aller Fahrzeuge, deren Typen als "VW-Kleinwagen" registriert sind.
Suche nach einem Unfall Fahrzeuge mit einer von mehreren möglichen Farben.
Vor allem das erste Beispiel wird sehr oft mit einer Unterabfrage versehen; vergleichen Sie dazu auch den folgenden Abschnitt zu EXISTS.
Hole die Liste aller Fahrzeuge vom Typ 'Volkswagen'.
SELECT * FROM Fahrzeug WHERE Fahrzeugtyp_ID IN ( SELECT ID FROM Fahrzeugtyp WHERE Hersteller_ID = 1 );
Dabei wird zuerst mit der Unterabfrage eine Liste aller Fahrzeugtypen-IDs für den Hersteller 1 (= Volkswagen) zusammengestellt; diese wird dann für den Vergleich über den IN-Parameter benutzt.
[Bearbeiten] EXISTS – schneller Vergleich mit einer Liste
Im Gegensatz zu den anderen Parametern der WHERE-Klausel arbeitet der EXISTS-Parameter nicht mit fest vorgegebenen Werten, sondern nur mit dem Ergebnis einer Abfrage, also einer Unterabfrage. Das letzte Beispiel zum IN-Parameter kann auch so formuliert werden:
Liste aller Fahrzeuge vom Typ 'Volkswagen'
SQL-Quelltext:
SELECT * FROM Fahrzeug fz WHERE EXISTS ( SELECT * FROM Fahrzeugtyp ft WHERE ft.Hersteller_ID = 1 AND fz.Fahrzeugtyp_ID = ft.ID );
Zu jedem Datensatz aus der Tabelle Fahrzeug wird zu dieser Fahrzeugtyp_ID eine Unterabfrage aus den Fahrzeugtypen erstellt: Wenn es dort einen Datensatz mit passender ID und Hersteller-ID 1 (= Volkswagen) gibt, gehört der Fahrzeug-Datensatz zur Auswahl, andernfalls nicht.
Da Unterabfragen zuerst ausgeführt werden, wird eine EXISTS-Prüfung in aller Regel schneller erledigt als die entsprechende IN-Prüfung: Bei EXISTS handelt es sich um eine Feststellung "ist überhaupt etwas vorhanden"; bei IN dagegen muss ein exakter Vergleich mit allen Werten einer Liste durchgeführt werden. Bei unserer kleinen Beispieldatenbank spielt das natürlich keine Rolle, aber bei einer "echten" Datenbank mit Millionen von Einträgen schon.
[Bearbeiten] Mehrere Bedingungen verknüpfen
Bei der WHERE-Klausel geht es darum festzustellen, ob ein bestimmter Datensatz Teil des Abfrageergebnisses ist oder nicht; bei der <search condition> handelt sich also um einen booleschen Ausdruck, d.h. einen Ausdruck, der einen der booleschen Werte WAHR oder FALSCH – TRUE bzw. FALSE – als Ergebnis hat. Nur bei einfachen Abfragen genügt dazu eine einzelne Bedingung; meistens müssen mehrere Bedingungen verknüpft werden (wie beim letzten Beispiel unter IS NULL).
Dazu gibt es die
booleschen Operatoren NOT, AND, OR.
[Bearbeiten] NOT als
Negation
Dieser Operator kehrt das Ergebnis um: aus TRUE wird FALSE, aus FALSE wird TRUE.
Siehe oben: keine Führerschein-Neulinge
SQL-Quelltext:
SELECT * FROM Versicherungsnehmer WHERE NOT (Fuehrerschein >= '01.01.2007');
[Bearbeiten] AND als
Konjunktion
Eine Bedingung, die durch eine AND-Verknüpfung gebildet wird, ist genau dann TRUE, wenn beide (bzw. alle) Bestandteile TRUE sind.
Die nach Alphabet erste Hälfte der Versicherungsnehmer eines PLZ-Bereichs
SQL-Quelltext:
SELECT ID, Name, Vorname, PLZ, Ort FROM Versicherungsnehmer WHERE PLZ BETWEEN '45000' AND '45999' AND Name < 'K';
[Bearbeiten] OR als
Adjunktion
Eine Bedingung, die durch eine OR-Verknüpfung gebildet wird, ist genau dann TRUE, wenn mindestens ein Bestandteil TRUE ist; dabei ist es gleichgültig, ob die anderen Bestandteile TRUE oder FALSE sind.
Die nach Alphabet erste Hälfte der Versicherungsnehmer und alle eines PLZ-Bereichs
SQL-Quelltext:
SELECT ID, Name, Vorname, PLZ, Ort FROM Versicherungsnehmer WHERE PLZ BETWEEN '45000' AND '45999' OR Name < 'K';
Bitte beachten Sie, dass der normale Sprachgebrauch "alle ... und alle ..." sagt. Gemeint ist nach logischen Begriffen aber, dass <Bedingung 1> erfüllt sein muss ODER <Bedingung 2> oder beide.
[Bearbeiten] XOR als
Kontravalenz
Eine Bedingung, die durch eine XOR-Verknüpfung zweier Bedingungen gebildet wird, ist genau dann TRUE, wenn ein Bestandteil TRUE ist, aber der andere Bestandteil FALSE ist – "ausschließendes oder", "entweder - oder". Diese Verknüpfung gibt es selten, z.B. bei MySql; ich erwähne es der Vollständigkeit halber.
Die nach Alphabet erste Hälfte der Versicherungsnehmer oder alle eines PLZ-Bereichs
SQL-Quelltext:
SELECT ID, Name, Vorname, PLZ, Ort FROM Versicherungsnehmer WHERE PLZ BETWEEN '45000' AND '45999' XOR Name < 'K';
Bitte beachten Sie, dass hier der normale Sprachgebrauch "oder" sagt und "entweder ... oder" meint.
Anstelle von XOR kann immer eine Kombination verwendet werden:
( <Bedingung 1> AND ( NOT <Bedingung 2> ) ) OR ( <Bedingung 2> AND ( NOT <Bedingung 1> ) )
[Bearbeiten] Klammern benutzen oder weglassen?
Bereits unter Ausführliche SELECT-Struktur habe ich auf folgende Hierarchie hingewiesen:
- NOT ist die engste Verbindung und wird vorrangig ausgewertet.
- AND ist die nächststärkere Verbindung und wird danach ausgewertet.
- OR ist die schwächste Verbindung und wird zuletzt ausgewertet.
- Was in Klammern steht, wird vor allem anderen ausgewertet.
Bitte setzen Sie im folgenden Beispiel Klammern an anderen Stellen oder streichen Sie Klammern, und vergleichen Sie die Ergebnisse.
SELECT ID, Name, Vorname, PLZ, Ort FROM Versicherungsnehmer WHERE NOT ( PLZ BETWEEN '45000' AND '45999' AND ( Name LIKE 'B%' OR Name LIKE 'K%' OR NOT Name CONTAINING 'ei' ) ) ORDER BY PLZ, Name;
Sie werden ziemlich unterschiedliche Ergebnisse feststellen. Es empfiehlt sich deshalb, an allen sinnvollen Stellen Klammern zu setzen – auch dort, wo sie nicht erforderlich sind – und das, was zusammengehört, durch Einrückungen sinnvoll zu gliedern.
[Bearbeiten] Zusammenfassung
In diesem Kapitel lernten wir neben dem Vergleich von Werten viele Möglichkeiten kennen, mit denen Bedingungen für Abfragen festgelegt werden können:
- Mit BETWEEN AND werden Werte innerhalb eines Bereichs geprüft.
- Mit LIKE und CONTAINS werden Werte gesucht, die mit vorgegebenen Werten teilweise übereinstimmen.
- Mit IS NULL werden null-Werte gesucht.
- Mit IN und EXISTS werden Spaltenwerte mit einer Liste verglichen.
Mit AND, OR, NOT werden Bedingungen zusammengefasst.