Aufbau Regulärer Ausdrücke
Dieser Abschnitt behandelt die Elemente und Regeln zum Aufbau Regulärer Ausdrücke in SQL.
Dieser Abschnitt behandelt die Elemente und Regeln zum Aufbau Regulärer Ausdrücke in SQL.
Innerhalb Regulärer Ausdrücke repräsentieren die meisten Zeichen sich selbst.Die einzige Ausnahme bilden die folgenden Zeichen:
[ ] ( ) | ^ - + * % _ ? { }
... und das Escape-Zeichen, sofern definiert.
Ein Regulärer Ausdruck, der keine Sonderzeichen oder Escape-Zeichen beinhaltet, findet nur Strings, die identisch zu sich selbst sind (abhängig von der verwendeten Collation).Das heißt, es agiert wie der ‘=
’-Operator:
'Apple' similar to 'Apple' -- true
'Apples' similar to 'Apple' -- false
'Apple' similar to 'Apples' -- false
'APPLE' similar to 'Apple' -- abhängig von der Collation
Die bekannten SQL-Wildcards ‘_
’ und ‘%
’ finden beliebige Einzelzeichen und Strings beliebiger Länge:
'Birne' similar to 'B_rne' -- true
'Birne' similar to 'B_ne' -- false
'Birne' similar to 'B%ne' -- true
'Birne' similar to 'Bir%ne%' -- true
'Birne' similar to 'Birr%ne' -- false
Beachten Sie, wie ‘%
’ auch den leeren String berücksichtigt.
Ein Bündel von Zeichen, die in Klammern eingeschlossen sind, definiert eine Zeichenklasse.Ein Zeichen in der Zeichenfolge entspricht einer Klasse im Muster, wenn das Zeichen Mitglied der Klasse ist:
'Citroen' similar to 'Cit[arju]oen' -- true
'Citroen' similar to 'Ci[tr]oen' -- false
'Citroen' similar to 'Ci[tr][tr]oen' -- true
Wie aus der zweiten Zeile ersichtlich ist, entspricht die Klasse nur einem einzigen Zeichen, nicht einer Sequenz.
Innerhalb einer Klassendefinition definieren zwei Zeichen, die durch einen Bindestrich verbunden sind, einen Bereich.Ein Bereich umfasst die beiden Endpunkte und alle Zeichen, die zwischen ihnen in der aktiven Sortierung liegen.Bereiche können überall in der Klassendefinition ohne spezielle Begrenzer platziert werden, um sie von den anderen Elementen zu trennen.
'Datte' similar to 'Dat[q-u]e' -- true
'Datte' similar to 'Dat[abq-uy]e' -- true
'Datte' similar to 'Dat[bcg-km-pwz]e' -- false
Die folgenden vordefinierten Zeichenklassen können auch in einer Klassendefinition verwendet werden:
[:ALPHA:]
Lateinische Buchstaben a..z und A..Z.Mit einer akzentunempfindlichen Sortierung stimmt diese Klasse auch mit akzentuierten Formen dieser Zeichen überein.
[:DIGIT:]
Dezimalziffern 0..9.
[:ALNUM:]
Gesamtheit aus [:ALPHA:]
und [:DIGIT:]
.
[:UPPER:]
Großgeschriebene Form der lateinischen Buchstaben A..Z.Findet auch kleingeschriebene Strings mit groß- und kleinschreibunempfindlicher Collation sowie akzentunempfindlicher Collation.
[:LOWER:]
Kleingeschriebene Form der lateinischen Buchstaben A..Z.Findet auch großgeschriebene Strings mit groß- und kleinschreibunempfindlicher Collation sowie akzentunempfindlicher Collation.
[:SPACE:]
Findet das Leerzeichen (ASCII 32).
[:WHITESPACE:]
Findet horizontalen Tabulator (ASCII 9), Zeilenvorschub (ASCII 10), vertikalen Tabulator (ASCII 11), Seitenvorschub (ASCII 12), Wagenrücklauf (ASCII 13) und Leerzeichen (ASCII 32).
Das Einbinden einer vordefinierten Klasse hat den gleichen Effekt wie das Einbinden all seiner Mitglieder.Vordefinierte Klassen sind nur in Klassendefinitionen erlaubt.Wenn Sie gegen eine vordefinierte Klasse prüfen und gegen nichts sonst, platzieren Sie ein zusätzliches Paar von Klammern um sie herum.
'Erdbeere' similar to 'Erd[[:ALNUM:]]eere' -- true
'Erdbeere' similar to 'Erd[[:DIGIT:]]eere' -- false
'Erdbeere' similar to 'Erd[a[:SPACE:]b]eere' -- true
'Erdbeere' similar to [[:ALPHA:]] -- false
'E' similar to [[:ALPHA:]] -- true
Wenn eine Klassendefinition mit einem Caret-Zeichen beginnt, wird alles, was folgt, aus der Klasse ausgeschlossen.Alle anderen Zeichen stimmen überein:
'Framboise' similar to 'Fra[^ck-p]boise' -- false
'Framboise' similar to 'Fr[^a][^a]boise' -- false
'Framboise' similar to 'Fra[^[:DIGIT:]]boise' -- true
If the caret is not placed at the start of the sequence, the class contains everything before the caret, except for the elements that also occur after the caret:
'Grapefruit' similar to 'Grap[a-m^f-i]fruit' -- true
'Grapefruit' similar to 'Grap[abc^xyz]fruit' -- false
'Grapefruit' similar to 'Grap[abc^de]fruit' -- false
'Grapefruit' similar to 'Grap[abe^de]fruit' -- false
'3' similar to '[[:DIGIT:]^4-8]' -- true
'6' similar to '[[:DIGIT:]^4-8]' -- false
Zuletzt sei noch erwähnt, dass die Wildcard-Zeichen ‘_
’ eine eigene Zeichenklasse sind, die einem beliebigen einzelnen Zeichen entspricht.
Ein Fragezeichen, direkt von einem weiteren Zeichen oder Klasse gefolgt, gibt an, dass das folgende Element gar nicht oder einmalig vorkommen darf:
'Hallon' similar to 'Hal?on' -- false
'Hallon' similar to 'Hal?lon' -- true
'Hallon' similar to 'Halll?on' -- true
'Hallon' similar to 'Hallll?on' -- false
'Hallon' similar to 'Halx?lon' -- true
'Hallon' similar to 'H[a-c]?llon[x-z]?' -- true
Ein Sternchen (‘*
’) unmittelbar nach einem Zeichen oder einer Klasse zeigt an, dass das vorangehende Element 0-mal oder öfter vorkommen kann, damit es übereinstimmt:
'Icaque' similar to 'Ica*que' -- true
'Icaque' similar to 'Icar*que' -- true
'Icaque' similar to 'I[a-c]*que' -- true
'Icaque' similar to '_*' -- true
'Icaque' similar to '[[:ALPHA:]]*' -- true
'Icaque' similar to 'Ica[xyz]*e' -- false
Ein Pluszeichen (‘+
’) unmittelbar nach einem Zeichen oder einer Klasse gibt an, dass das vorangehende Element mindestens einmal vorkommen muss, damit es übereinstimmt:
'Jujube' similar to 'Ju_+' -- true
'Jujube' similar to 'Ju+jube' -- true
'Jujube' similar to 'Jujuber+' -- false
'Jujube' similar to 'J[jux]+be' -- true
'Jujube' sililar to 'J[[:DIGIT:]]+ujube' -- false
Wenn auf ein Zeichen oder eine Klasse eine Zahl in geschweiften Klammern folgt (‘{
’ und ‘}
’), muss sie genau so oft wiederholt werden, damit sie übereinstimmt:
'Kiwi' similar to 'Ki{2}wi' -- false
'Kiwi' similar to 'K[ipw]{2}i' -- true
'Kiwi' similar to 'K[ipw]{2}' -- false
'Kiwi' similar to 'K[ipw]{3}' -- true
Wenn der Zahl ein Komma folgt (‘,
’), muss das Element mindestens so oft wiederholt werden, damit es übereinstimmt:
'Limone' similar to 'Li{2,}mone' -- false
'Limone' similar to 'Li{1,}mone' -- true
'Limone' similar to 'Li[nezom]{2,}' -- true
Wenn die geschweiften Klammern zwei durch ein Komma getrennte Zahlen enthalten, wobei die zweite Zahl nicht kleiner als die erste ist, muss das Element mindestens die erste Zahl und höchstens die zweite Zahl wiederholt werden, um zu entsprechen:
'Mandarijn' similar to 'M[a-p]{2,5}rijn' -- true
'Mandarijn' similar to 'M[a-p]{2,3}rijn' -- false
'Mandarijn' similar to 'M[a-p]{2,3}arijn' -- true
Die Bezeichner ‘?
’, ‘*
’ und ‘+
’ sind Kurzschreibweisen für {0,1}
, {0,}
und {1,}
.
Reguläre Ausdrücke können Oder-verknüpft werden mittels ‘|
’-Operator.Eine Gesamtübereinstimmung tritt auf, wenn die Argumentzeichenkette mit mindestens einem Term übereinstimmt.
'Nektarin' similar to 'Nek|tarin' -- false
'Nektarin' similar to 'Nektarin|Persika' -- true
'Nektarin' similar to 'M_+|N_+|P_+' -- true
Ein oder mehrere Teile der regulären Ausdrücke können in Unterausdrücke gruppiert werden (auch Untermuster genannt), indem diese in runde Klammern eingeschlossen werden.Ein Unterausdruck ist ein eigener regulärer Ausdruck.Dieser kann alle erlaubten Elemente eines regulären Ausdrucks enthalten, und auch eigene Bezeichner.
'Orange' similar to 'O(ra|ri|ro)nge' -- true
'Orange' similar to 'O(r[a-e])+nge' -- true
'Orange' similar to 'O(ra){2,4}nge' -- false
'Orange' similar to 'O(r(an|in)g|rong)?e' -- true
IS [NOT] DISTINCT FROM
DSQL, PSQL
<operand1> IS [NOT] DISTINCT FROM <operand2>
Zwei Operanden werden als DISTINCT angesehen, wenn sie unterschiedliche Werte besitzen oder wenn einer NULL
ist und der andere nicht-NULL
.Sie werden als NOT DISTINCT angesehen, wenn sie den gleichen Wert besitzen oder beide Operanden NULL
sind.
IS [NOT] DISTINCT FROM
liefert immer TRUE oder FALSE und niemals UNKNOWN (NULL) (unbekannter Wert).Die Operatoren ‘=
’ und ‘<>
’ geben umgekehrt UNKNOWN (NULL) zurück, wenn einer oder beide Operanden NULL sind.
Operandenwerte |
Ergebnis verschiedener Prädikate |
|||
---|---|---|---|---|
|
|
|
|
|
Gleiche Werte |
|
|
|
|
Verschiedene Werte |
|
|
|
|
Beide |
|
|
|
|
Einer |
|
|
|
|
SELECT ID, NAME, TEACHER
FROM COURSES
WHERE START_DAY IS NOT DISTINCT FROM END_DAY;
-- PSQL-Fragment
IF (NEW.JOB IS DISTINCT FROM OLD.JOB)
THEN POST_EVENT 'JOB_CHANGED';
IS [NOT]
DSQL, PSQL
<value> IS [NOT] { TRUE | FALSE | UNKNOWN }
Das IS
-Prädikat mit booleschen Literalwerten prüft, ob der Ausdruck auf der linken Seite mit dem booleschen Wert auf der rechten Seite übereinstimmt.Der Ausdruck auf der linken Seite muss vom Typ BOOLEAN
sein, sonst kommt es zu einer Ausnahme.
Das IS [NOT] UNKNOWN
entspricht IS [NOT] NULL
.
Note
|
Die rechte Seite des Prädikats akzeptiert nur die Literale |
-- FALSE-Wert prüfen
SELECT * FROM TBOOL WHERE BVAL IS FALSE;
ID BVAL
============= =======
2 <false>
-- UNKNOWN-Wert prüfen
SELECT * FROM TBOOL WHERE BVAL IS UNKNOWN;
ID BVAL
============= =======
3 <null>
IS [NOT] NULL
DSQL, PSQL, ESQL
<value> IS [NOT] NULL
Da NULL
kein Wert ist, sind diese Operatoren keine Vergleichsoperatoren.Das Prädikat IS [NOT] NULL
prüft die Behauptung, dass der Ausdruck auf der linken Seite einen Wert (IS NOT NULL) oder keinen Wert hat (IS NULL).
Suche nach Verkäufen, die kein Versanddatum besitzen:
SELECT * FROM SALES
WHERE SHIP_DATE IS NULL;
Note
|
Hinweis bezüglich des IS-Prädikates
Bis einschließlich Firebird 2.5, hat das Prädikat |
Diese Gruppe von Prädikaten umfasst diejenigen, die Unterabfragen verwenden, um Werte für alle Arten von Zusicherungen in Suchbedingungen zu übermitteln.Existenzielle Prädikate werden so genannt, weil sie verschiedene Methoden verwenden, um auf existence oder non-existence einer Bedingung zu testen, und TRUE
zurückgeben, wenn die Existenz oder Nichtexistenz bestätigt wird oder FALSE
andernfalls.
EXISTS
DSQL, PSQL, ESQL
[NOT] EXISTS (<select_stmt>)
Das Prädikat EXISTS
verwendet als Argument einen Unterabfrageausdruck.Es gibt TRUE
zurück, wenn das Ergebnis der Unterabfrage mindestens eine Zeile enthalten würde; andernfalls gibt es FALSE
zurück.
NOT EXISTS
gibt FALSE
zurück, wenn das Ergebnis der Unterabfrage mindestens eine Zeile enthalten würde; andernfalls gibt es TRUE
zurück.
Note
|
Die Unterabfrage kann mehrere Spalten enthalten, oder |
Finde die Mitarbeiter, die Projekte haben.
SELECT *
FROM employee
WHERE EXISTS(SELECT *
FROM employee_project ep
WHERE ep.emp_no = employee.emp_no)
Finde die Mitarbeiter, die keine Projekte haben.
SELECT *
FROM employee
WHERE NOT EXISTS(SELECT *
FROM employee_project ep
WHERE ep.emp_no = employee.emp_no)
IN
DSQL, PSQL, ESQL
<value> [NOT] IN (<select_stmt> | <value_list>) <value_list> ::= <value_1> [, <value_2> …]
Das Prädikat IN
prüft, ob der Wert des Ausdrucks auf der linken Seite im Wertesatz der rechten Seite vorkommt.Der Wertesatz darf nicht mehr als 1500 Elemente enthalten.Das IN
-Prädikat kann mit folgender äquivalenter Form ersetzt werden:
(<value> = <value_1> [OR <value> = <value_2> …]) <value> = { ANY | SOME } (<select_stmt>)
Wenn das Prädikat IN
als Suchbedingung in DML-Abfragen verwendet wird, kann der Firebird-Optimizer einen Index auf die Suchspalte nutzen, sofern einer vorhanden ist.
In seiner zweiten Form prüft das Prädikat IN
, ob der linke Ausdruckswert im Ergebnis der Unterabfrage vorhanden ist (oder nicht vorhanden, wenn NOT IN
verwendet wird).
Die Unterabfrage darf nur eine Spalte abfragen, andernfalls wird es zum Fehler “count of column list and variable list do not match” kommen.
Abfragen, die das Prädikat IN
mit einer Unterabfrage verwenden, können durch eine ähnliche Abfrage mittels des EXISTS
-Prädikates ersetzt werden.Zum Beispiel folgende Abfrage:
SELECT
model, speed, hd
FROM PC
WHERE
model IN (SELECT model
FROM product
WHERE maker = 'A');
kann ersetzt werden mittels EXISTS-Prädikat:
SELECT
model, speed, hd
FROM PC
WHERE
EXISTS (SELECT *
FROM product
WHERE maker = 'A'
AND product.model = PC.model);
Jedoch gilt zu beachten, dass eine Abfrage mittels NOT IN
und einer Unterabfrage nicht immer das gleiche Ergebnis zurückliefert wie sein Gegenpart mit NOT EXISTS
.Dies liegt daran, dass EXISTS
immer TRUE oder FALSE zurückgibt, wohingegen IN
NULL
in diesen beiden Fällen zurückliefert:
wenn der geprüfte Wert NULL
ist und die IN ()
-Liste nicht leer ist
wenn der geprüfte Wert keinen Treffer in der IN ()
-Liste enthält und mindestens ein Element NULL
ist.
Nur in diesen beiden Fällen wird IN ()
NULL
zurückgeben, während das EXISTS
-Prädikat FALSE
zurückgibt ('keine passende Zeile gefunden', engl. 'no matching row found').In einer Suche oder, zum Beispiel in einem IF (…)
-Statement, bedeuten beide Ergebnisse einen “Fehler” und es macht damit keinen Unterschied.
Aber für die gleichen Daten gibt NOT IN ()
NULL
zurück, während NOT EXISTS
TRUE
zurückgibt, was das Gegenteilige Ergebnis ist.
Schauen wir uns das folgendes Beispiel an:
-- Suche nach Bürgern die nicht am gleichen Tag wie eine
-- berühmte New Yorker Persönlichkeit geboren wurden
SELECT P1.name AS NAME
FROM Personnel P1
WHERE P1.birthday NOT IN (SELECT C1.birthday
FROM Celebrities C1
WHERE C1.birthcity = 'New York');
Nehmen wir nun an, dass die Liste der New Yorker Berühmtheiten nicht leer ist und mindestens einen NULL-Geburtstag aufweist.Dann gilt für alle Bürger, die nicht am gleichen Tag mit einer Berühmtheit Geburtstag haben, dass NOT IN
NULL
zurückgibt, da dies genau das ist was IN
tut.Die Suchbedingung wurde nicht erfüllt und die Bürger werden nicht im Ergebnis des SELECT
berücksichtigt, da die Aussage falsch ist.
Bürger, die am gleichen Tag wie eine Berühmtheit Geburtstag feiern, wird NOT IN
korrekterweise FALSE
zurückgeben, womit diese ebenfalls aussortiert werden, und damit keine Zeile zurückgegeben wird.
Wird die Form NOT EXISTS
verwendet:
-- Suche nach Bürgern, die nicht am gleichen Tag wie eine
-- berühmte New Yorker Persönlichkeit geboren wurden
SELECT P1.name AS NAME
FROM Personnel P1
WHERE NOT EXISTS (SELECT *
FROM Celebrities C1
WHERE C1.birthcity = 'New York'
AND C1.birthday = P1.birthday);
nicht-Übereinstimmungen werden im NOT EXISTS
-Ergebnis TRUE
erhalten und ihre Datensätze landen im Rückgabesatz.
Tip
|
Wenn bei der Suche nach einer Nichtübereinstimmung die Möglichkeit besteht, dass |
Finde Mitarbeiter mit den Namen “Pete”, “Ann” und “Roger”:
SELECT *
FROM EMPLOYEE
WHERE FIRST_NAME IN ('Pete', 'Ann', 'Roger');
Finde alle Computer, die deren Hersteller mit dem Buchstaben “A” beginnt:
SELECT
model, speed, hd
FROM PC
WHERE
model IN (SELECT model
FROM product
WHERE maker STARTING WITH 'A');
SINGULAR
DSQL, PSQL, ESQL
[NOT] SINGULAR (<select_stmt>)
Das Prädikat SINGULAR
nimmt eine Unterabfrage als Argument und wertet sie als TRUE, wenn die Unterabfrage genau eine Ergebniszeile zurückgibt; andernfalls wird das Prädikat als FALSE ausgewertet.Die Unterabfrage kann mehrere Ausgabespalten auflisten, da die Zeilen sowieso nicht zurückgegeben werden.Sie werden nur auf (singuläre) Existenz geprüft.Der Kürze halber wird normalerweise ‘SELECT *
’ angegeben.Das Prädikat SINGULAR
kann nur zwei Werte zurückgeben: TRUE
oder FALSE
.
Finden Sie die Mitarbeiter, die nur ein Projekt haben.
SELECT *
FROM employee
WHERE SINGULAR(SELECT *
FROM employee_project ep
WHERE ep.emp_no = employee.emp_no)
Ein Quantifizierer ist ein logischer Operator, der die Anzahl der Objekte festlegt, für die diese Behauptung wahr ist.Es ist keine numerische Größe, sondern eine logische, die die Behauptung mit dem vollen Satz möglicher Objekte verbindet.Solche Prädikate basieren auf logischen universellen und existentiellen Quantifizierern, die in der formalen Logik erkannt werden.
In Unterabfrageausdrücken ermöglichen quantifizierte Prädikate den Vergleich einzelner Werte mit den Ergebnissen von Unterabfragen;sie haben die folgende gemeinsame Form:
<value expression> <comparison operator> <quantifier> <subquery>
ALL
DSQL, PSQL, ESQL
<value> <op> ALL (<select_stmt>)
Wenn der ALL
-Quantifizierer verwendet wird, ist das Prädikat TRUE, wenn jeder Wert, der von der Unterabfrage zurückgegeben wird, die Bedingung des Prädikates in der Hauptabfrage erfüllt ist.
Zeige nur jene Kunden an, deren Bewertungen höher sind als die Bewertung jedes Kunden in Paris.
SELECT c1.*
FROM Customers c1
WHERE c1.rating > ALL
(SELECT c2.rating
FROM Customers c2
WHERE c2.city = 'Paris')
Important
|
Wenn die Unterabfrage einen leeren Satz zurückgibt, ist das Prädikat TRUE für jeden linken Wert, unabhängig vom Operator.Dies mag widersprüchlich erscheinen, denn jeder linke Wert wird gegenüber dem rechten betrachtet als: kleiner als, größer als, gleich sowie ungleich. Dennoch passt dies perfekt in die formale Logik: Wenn der Satz leer ist, ist das Prädikat 0 mal wahr, d.h. für jede Zeile im Satz. |
ANY
and SOME
DSQL, PSQL, ESQL
<value> <op> {ANY | SOME} (<select_stmt>)
Die Quantifizierer ANY
und SOME
sind in ihrem Verhalten identisch.Offensichtlich sind beide im SQL-Standard vorhanden, so dass sie austauschbar verwendet werden können, um die Lesbarkeit der Operatoren zu verbessern.Wird der ANY
- oder SOME
-Quantifizierer verwendet, ist das Prädikat TRUE, wenn einer der zurückgegebenen Werte der Unterabfrage die Suchbedingung der Hauptabfrage erfüllt.Gibt die Unterabfrage keine Zeile zurück, wird das Prädikat automtisch als FALSE angesehen.
Zeige nur die Kunden, deren Bewertungen höher sind als die eines oder mehrerer Kunden in Rom.
SELECT *
FROM Customers
WHERE rating > ANY
(SELECT rating
FROM Customers
WHERE city = 'Rome')