PLAN
Eine PLAN
-Klausel ermöglicht es dem Benutzer, die Operation manuell zu optimieren.
DELETE FROM Submissions
WHERE date_entered < '1-Jan-2002'
PLAN (Submissions INDEX ix_subm_date);
Beispiele für SELECT-Abfragen mit verschiedenen Arten von Spaltenlisten
PLAN
Eine PLAN
-Klausel ermöglicht es dem Benutzer, die Operation manuell zu optimieren.
DELETE FROM Submissions
WHERE date_entered < '1-Jan-2002'
PLAN (Submissions INDEX ix_subm_date);
ORDER BY
und ROWS
Die ORDER BY
-Klausel ordnet die Menge, bevor das eigentliche Löschen stattfindet.Es macht nur in Kombination mit ROWS
Sinn, ist aber auch ohne gültig.
Die ROWS
-Klausel begrenzt die Anzahl der zu löschenden Zeilen.Für die Argumente m und n können ganzzahlige Literale oder beliebige ganzzahlige Ausdrücke verwendet werden.
Wenn ROWS
ein Argument hat, m, werden die zu löschenden Zeilen auf die ersten m Zeilen beschränkt.
Wenn m > die Anzahl der verarbeiteten Zeilen ist, wird der gesamte Satz von Zeilen gelöscht
Bei m = 0 werden keine Zeilen gelöscht
Wenn m < 0, tritt ein Fehler auf und das Löschen schlägt fehl
Wenn zwei Argumente verwendet werden, m und n, begrenzt ROWS
die zu löschenden Zeilen auf Zeilen von m bis einschließlich n.Beide Argumente sind ganze Zahlen und beginnen bei 1.
Wenn m > die Anzahl der verarbeiteten Zeilen ist, werden keine Zeilen gelöscht
Wenn m > 0 und <= die Anzahl der Zeilen im Set und n außerhalb dieser Werte liegt, werden Zeilen von m bis zum Ende des Sets gelöscht
Wenn m < 1 oder n < 1 ist, tritt ein Fehler auf und das Löschen schlägt fehl
Wenn n = m - 1, werden keine Zeilen gelöscht
Wenn n < m -1, tritt ein Fehler auf und das Löschen schlägt fehl
Löschen des ältesten Kaufs:
DELETE FROM Purchases
ORDER BY date ROWS 1;
Löschen des/der höchsten Custno(s):
DELETE FROM Sales
ORDER BY custno DESC ROWS 1 to 10;
Löschen aller Verkäufe, ORDER BY
-Klausel sinnlos:
DELETE FROM Sales
ORDER BY custno DESC;
Löschen eines Datensatzes am Ende beginnend, also ab Z…:
DELETE FROM popgroups
ORDER BY name DESC ROWS 1;
Löschen der fünf ältesten Gruppen:
DELETE FROM popgroups
ORDER BY formed ROWS 5;
Da keine Sortierung (ORDER BY
) angegeben ist, werden 8 gefundene Datensätze, beginnend mit dem fünften, gelöscht:
DELETE FROM popgroups
ROWS 5 TO 12;
RETURNING
Eine DELETE
-Anweisung, die höchstens eine Zeile entfernt, kann optional eine RETURNING
-Klausel enthalten, um Werte aus der gelöschten Zeile zurückzugeben.Die Klausel, falls vorhanden, muss nicht alle Spalten der Relation enthalten und kann auch andere Spalten oder Ausdrücke enthalten.
Der Benutzer, der die Anweisung ausführt, benötigt SELECT
-Berechtigungen für die in der RETURNING
-Klausel angegebenen Spalten.
Die Syntax der returning_list ähnelt der Spaltenliste einer SELECT
-Klausel.Es ist möglich, alle Spalten mit *
oder table_name.*
zu referenzieren.
Note
|
|
DELETE FROM Scholars
WHERE firstname = 'Henry' and lastname = 'Higgins'
RETURNING lastname, fullname, id;
DELETE FROM Scholars
WHERE firstname = 'Henry' and lastname = 'Higgins'
RETURNING *;
DELETE FROM Dumbbells
ORDER BY iq DESC
ROWS 1
RETURNING lastname, iq into :lname, :iq;
MERGE
Zusammenführen von Daten aus einem Quellsatz in eine Zielrelation
DSQL, PSQL
MERGE INTO target [[AS] target_alias] USING <source> [[AS] source_alias] ON <join_condition> <merge_when> [<merge_when> ...] [RETURNING <returning_list> [INTO <variables>]] <merge_when> ::= <merge_when_matched> | <merge_when_not_matched> <merge_when_matched> ::= WHEN MATCHED [ AND <condition> ] THEN { UPDATE SET <assignment-list> | DELETE } <merge_when_not_matched> ::= WHEN NOT MATCHED [ AND <condition> ] THEN INSERT [( <column_list> )] [<override_opt>] VALUES ( <value_list> ) <source> ::= tablename | (<select_stmt>) <assignment_list ::= col_name = <m_value> [, <col_name> = <m_value> ...]] <override_opt> ::= OVERRIDING {USER | SYSTEM} VALUE <column_list> ::= colname [, colname ...] <value_list> ::= <m_value> [, <m_value> ...] <m_value> ::= <value_expression> | DEFAULT <returning_list> ::= * | <output_column> [, <output_column] <output_column> ::= target.* | NEW.* | OLD.* | <return_expression> [COLLATE collation] [[AS] alias] <return_expression> ::= <value_expression> | [target.]col_name | NEW.col_name | OLD.col_name <value_expression> ::= <literal> | <context-variable> | any other expression returning a single value of a Firebird data type or NULL <variables> ::= [:]varname [, [:]varname ...]
Argument | Beschreibung |
---|---|
target |
Name der Zielbeziehung (Tabelle oder aktualisierbare Sicht) |
source |
Datenquelle.Dies kann eine Tabelle, eine Ansicht, eine gespeicherte Prozedur oder eine abgeleitete Tabelle sein |
target_alias |
Alias für die Zielbeziehung (Tabelle oder aktualisierbare Ansicht) |
source_alias |
Alias für die Quellrelation oder Menge |
join_conditions |
Die ( |
condition |
Zusätzliche Testbedingung in der Klausel |
tablename |
Tabellen- oder Ansichtsname |
select_stmt |
Select-Anweisung der abgeleiteten Tabelle |
col_name |
Name einer Spalte in der Zielrelation |
value_expression |
Der einer Spalte in der Zieltabelle zugewiesene Wert.Dieser Ausdruck kann ein Literalwert, eine PSQL-Variable, eine Spalte aus der Quelle oder eine kompatible Kontextvariable sein |
return_expression |
Der in der |
ret_alias |
Alias für den Wertausdruck in der |
varname |
Name einer lokalen PSQL-Variablen |
Die 'MERGE'-Anweisung führt Datensätze aus der Quelle in eine Zieltabelle oder eine aktualisierbare Sicht zusammen.Die Quelle kann eine Tabelle, ein View oder “alles, was mit SELECT
abfragen” können.Jeder Quelldatensatz wird verwendet, um einen oder mehrere Zieldatensätze zu aktualisieren, einen neuen Datensatz in die Zieltabelle einzufügen, einen Datensatz aus der Zieltabelle zu löschen oder nichts zu tun.
Welche Aktion ausgeführt wird, hängt von der angegebenen Join-Bedingung, der/den WHEN
-Klausel(n) und der - optionalen - Bedingung in der WHEN
-Klausel ab.Die Join-Bedingung und die Bedingung im WHEN
enthalten normalerweise einen Vergleich von Feldern in den Quell- und Zielbeziehungen.
Mehrere WHEN MATCHED
- und WHEN NOT MATCHED
-Klauseln sind zulässig.Für jede Zeile in der Quelle werden die WHEN
-Klauseln in der Reihenfolge überprüft, in der sie in der Anweisung angegeben sind.Wenn die Bedingung in der WHEN
-Klausel nicht als wahr ausgewertet wird, wird die Klausel übersprungen und die nächste Klausel wird geprüft.Dies wird getan, bis die Bedingung für eine WHEN
-Klausel wahr ist oder eine WHEN
-Klausel ohne Bedingung zutrifft oder es keine WHEN
-Klauseln mehr gibt.Wenn eine übereinstimmende Klausel gefunden wird, wird die mit der Klausel verknüpfte Aktion ausgeführt.Für jede Zeile in der Quelle wird höchstens eine Aktion ausgeführt.Wenn die Klausel WHEN MATCHED
vorhanden ist und mehrere Datensätze mit einem einzigen Datensatz in der Zieltabelle übereinstimmen, wird ein Fehler ausgegeben.
Warning
|
Mindestens eine
Derzeit gibt die Variable |
RETURNING
-KlauselEine MERGE
-Anweisung, die höchstens eine Zeile betrifft, kann eine RETURNING
-Klausel enthalten, um hinzugefügte, geänderte oder entfernte Werte zurückzugeben.Wenn eine RETURNING
-Klausel vorhanden ist und mehr als ein übereinstimmender Datensatz gefunden wird, wird ein Fehler “multiple rows in singleton select” ausgegeben.Die RETURNING
-Klausel kann beliebige Spalten aus der Zieltabelle (oder aktualisierbaren View) sowie andere Spalten (zB aus der Quelle) und Ausdrücke enthalten.
Der Benutzer, der die Anweisung ausführt, benötigt SELECT
-Berechtigungen für die in der RETURNING
-Klausel angegebenen Spalten.
Die optionale Unterklausel INTO
ist nur in PSQL gültig.
Note
|
Die Einschränkung, dass |
Spaltennamen können durch das Präfix "OLD" oder "NEW" qualifiziert werden, um genau zu definieren, welcher Wert zurückgegeben werden soll: vor oder nach der Änderung. Die zurückgegebenen Werte enthalten die Änderungen, die von BEFORE
-Triggern vorgenommen wurden.
Die Syntax der returning_list ähnelt der Spaltenliste einer SELECT
-Klausel.Es ist möglich, alle Spalten mit *
oder table_name.*
, NEW.*
und/oder OLD.*
zu referenzieren.
Für die Aktion UPDATE
oder INSERT
verhalten sich unqualifizierte Spaltennamen oder solche, die durch den Zieltabellennamen oder Alias qualifiziert sind, als ob sie durch NEW
qualifiziert wären, während sie für die DELETE
Aktion wie durch OLD
qualifiziert wären.
Das folgende Beispiel modifiziert das vorherige Beispiel, um eine Zeile zu betreffen, und fügt eine RETURNING
-Klausel hinzu, um die alte und neue Warenmenge sowie die Differenz zwischen diesen Werten zurückzugeben.
MERGE
mit einer RETURNING
-KlauselMERGE INTO PRODUCT_INVENTORY AS TARGET
USING (
SELECT
SL.ID_PRODUCT,
SUM(SL.QUANTITY)
FROM SALES_ORDER_LINE SL
JOIN SALES_ORDER S ON S.ID = SL.ID_SALES_ORDER
WHERE S.BYDATE = CURRENT_DATE
AND SL.ID_PRODUCT =: ID_PRODUCT
GROUP BY 1
) AS SRC (ID_PRODUCT, QUANTITY)
ON TARGET.ID_PRODUCT = SRC.ID_PRODUCT
WHEN MATCHED AND TARGET.QUANTITY - SRC.QUANTITY <= 0 THEN
DELETE
WHEN MATCHED THEN
UPDATE SET
TARGET.QUANTITY = TARGET.QUANTITY - SRC.QUANTITY,
TARGET.BYDATE = CURRENT_DATE
RETURNING OLD.QUANTITY, NEW.QUANTITY, SRC.QUANTITY
INTO : OLD_QUANTITY, :NEW_QUANTITY, :DIFF_QUANTITY
MERGE
Aktualisieren Sie Bücher, wenn vorhanden, oder fügen Sie einen neuen Datensatz hinzu, wenn Sie abwesend sind
MERGE INTO books b
USING purchases p
ON p.title = b.title and p.type = 'bk'
WHEN MATCHED THEN
UPDATE SET b.desc = b.desc || '; ' || p.desc
WHEN NOT MATCHED THEN
INSERT (title, desc, bought) values (p.title, p.desc, p.bought);
Verwenden einer abgeleiteten Tabelle
MERGE INTO customers c
USING (SELECT * from customers_delta WHERE id > 10) cd
ON (c.id = cd.id)
WHEN MATCHED THEN
UPDATE SET name = cd.name
WHEN NOT MATCHED THEN
INSERT (id, name) values (cd.id, cd.name);
Zusammen mit einem rekursiven CTE
MERGE INTO numbers
USING (
WITH RECURSIVE r(n) AS (
SELECT 1 FROM rdb$database
UNION ALL
SELECT n+1 FROM r WHERE n < 200
)
SELECT n FROM r
) t
ON numbers.num = t.n
WHEN NOT MATCHED THEN
INSERT(num) VALUES(t.n);
Verwenden der DELETE
-Klausel
MERGE INTO SALARY_HISTORY
USING (
SELECT EMP_NO
FROM EMPLOYEE
WHERE DEPT_NO = 120) EMP
ON SALARY_HISTORY.EMP_NO = EMP.EMP_NO
WHEN MATCHED THEN DELETE
Im folgenden Beispiel wird die Tabelle "PRODUCT_INVENTORY" täglich basierend auf den in der Tabelle "SALES_ORDER_LINE" verarbeiteten Bestellungen aktualisiert.Wenn der Lagerbestand des Produkts auf null oder darunter sinken würde, wird die Zeile für dieses Produkt aus der Tabelle PRODUCT_INVENTORY
entfernt.
MERGE INTO PRODUCT_INVENTORY AS TARGET
USING (
SELECT
SL.ID_PRODUCT,
SUM (SL.QUANTITY)
FROM SALES_ORDER_LINE SL
JOIN SALES_ORDER S ON S.ID = SL.ID_SALES_ORDER
WHERE S.BYDATE = CURRENT_DATE
GROUP BY 1
) AS SRC (ID_PRODUCT, QUANTITY)
ON TARGET.ID_PRODUCT = SRC.ID_PRODUCT
WHEN MATCHED AND TARGET.QUANTITY - SRC.QUANTITY <= 0 THEN
DELETE
WHEN MATCHED THEN
UPDATE SET
TARGET.QUANTITY = TARGET.QUANTITY - SRC.QUANTITY,
TARGET.BYDATE = CURRENT_DATE
EXECUTE PROCEDURE
Ausführen einer gespeicherten Prozedur
DSQL, ESQL, PSQL
EXECUTE PROCEDURE procname [{ <inparam-list | ( <inparam-list> ) }] [RETURNING_VALUES { <outvar-list> | ( <outvar-list ) }] <inparam-list> ::= <inparam> [, <inparam> ...] <outvar-list> ::= <outvar> [, <outvar> ...] <outvar> ::= [:]varname
Argument | Beschreibung |
---|---|
procname |
Name der gespeicherten Prozedur |
inparam |
Ein Ausdruck, der den deklarierten Datentyp eines Eingabeparameters auswertet |
varname |
Eine PSQL-Variable, um den Rückgabewert zu erhalten |
Führt eine ausführbare gespeicherte Prozedur aus, nimmt eine Liste mit einem oder mehreren Eingabeparametern, falls diese für die Prozedur definiert sind, und gibt einen einzeiligen Satz von Ausgabewerten zurück, wenn sie für die Prozedur definiert sind.
Die EXECUTE PROCEDURE
-Anweisung wird am häufigsten verwendet, um den Stil gespeicherter Prozeduren aufzurufen, die geschrieben werden, um auf der Serverseite eine Aufgabe zur Datenänderung auszuführen – solche, die keine SUSPEND
-Anweisungen in ihrem Code enthalten.Sie können so konzipiert sein, dass sie eine Ergebnismenge, die nur aus einer Zeile besteht, die normalerweise über einen Satz von RETURNING_VALUES()
-Variablen an eine andere gespeicherte Prozedur übergeben wird, die sie aufruft, zurückgeben.Clientschnittstellen verfügen normalerweise über einen API-Wrapper, der die Ausgabewerte in einen Einzelzeilenpuffer abrufen kann, wenn EXECUTE PROCEDURE
in DSQL aufgerufen wird.
Das Aufrufen des anderen Stils von Stored Procedures - einer “selectable” - ist mit EXECUTE PROCEDURE
möglich, aber es gibt nur die erste Zeile eines Ausgabesatzes zurück, der mit ziemlicher Sicherheit mehrzeilig ist.Auswählbare gespeicherte Prozeduren sind so konzipiert, dass sie durch eine SELECT
-Anweisung aufgerufen werden und eine Ausgabe erzeugen, die sich wie eine virtuelle Tabelle verhält.
Note
|
|
EXECUTE PROCEDURE
In PSQL mit optionalen Doppelpunkten und ohne optionale Klammern:
EXECUTE PROCEDURE MakeFullName
:FirstName, :MiddleName, :LastName
RETURNING_VALUES :FullName;
In Firebirds Befehlszeilen-Dienstprogramm isql, mit Literalparametern und optionalen Klammern:
EXECUTE PROCEDURE MakeFullName ('J', 'Edgar', 'Hoover');
Note
|
In DSQL (zB in isql) wird |
Ein PSQL-Beispiel mit Ausdrucksparametern und optionalen Klammern:
EXECUTE PROCEDURE MakeFullName
('Mr./Mrs. ' || FirstName, MiddleName, upper(LastName))
RETURNING_VALUES (FullName);
EXECUTE BLOCK
Erstellen eines "anonymen" Blocks von PSQL-Code in DSQL zur sofortigen Ausführung
DSQL
EXECUTE BLOCK [(<inparams>)] [RETURNS (<outparams>)] <psql-module-body> <inparams> ::= <param_decl> = ? [, <inparams> ] <outparams> ::= <param_decl> [, <outparams>] <param_decl> ::= paramname <domain_or_non_array_type> [NOT NULL] [COLLATE collation] <domain_or_non_array_type> ::= !! Siehe auch Skalardatentypen-Syntax !! <psql-module-body> ::= !! Siehe auch Syntax für Modul-Bodys !!
Argument | Beschreibung |
---|---|
param_decl |
Name und Beschreibung eines Eingabe- oder Ausgabeparameters |
paramname |
Der Name eines Eingangs- oder Ausgangsparameters des Verfahrensblocks, bis zu 63 Zeichen lang.Der Name muss unter Ein- und Ausgabeparametern und lokalen Variablen im Block eindeutig sein |
collation |
Sortierreihenfolge |
Führt einen Block von PSQL-Code wie eine gespeicherte Prozedur aus, optional mit Eingabe- und Ausgabeparametern und Variablendeklarationen.Dies ermöglicht dem Benutzer, PSQL "on-the-fly" in einem DSQL-Kontext auszuführen.
In diesem Beispiel werden die Zahlen 0 bis 127 und die entsprechenden ASCII-Zeichen in die Tabelle ASCIITABLE
eingefügt:
EXECUTE BLOCK
AS
declare i INT = 0;
BEGIN
WHILE (i < 128) DO
BEGIN
INSERT INTO AsciiTable VALUES (:i, ascii_char(:i));
i = i + 1;
END
END
Das nächste Beispiel berechnet das geometrische Mittel zweier Zahlen und gibt es an den Benutzer zurück:
EXECUTE BLOCK (x DOUBLE PRECISION = ?, y DOUBLE PRECISION = ?)
RETURNS (gmean DOUBLE PRECISION)
AS
BEGIN
gmean = SQRT(x*y);
SUSPEND;
END
Da dieser Block Eingangsparameter hat, muss er zuerst vorbereitet werden.Anschließend können die Parameter eingestellt und der Block ausgeführt werden.Es hängt von der Client-Software ab, wie dies zu tun ist und ob es überhaupt möglich ist – siehe die Hinweise unten.
Unser letztes Beispiel nimmt zwei ganzzahlige Werte an, kleinste
und größte
.Für alle Zahlen im Bereich kleinste
…größte
gibt der Block die Zahl selbst, ihr Quadrat, ihren Kubus und ihre vierte Potenz aus.
EXECUTE BLOCK (smallest INT = ?, largest INT = ?)
RETURNS (number INT, square BIGINT, cube BIGINT, fourth BIGINT)
AS
BEGIN
number = smallest;
WHILE (number <= largest) DO
BEGIN
square = number * number;
cube = number * square;
fourth = number * cube;
SUSPEND;
number = number + 1;
END
END
Auch hier hängt es von der Client-Software ab, ob und wie Sie die Parameterwerte einstellen können.
Die Ausführung eines Blocks ohne Eingabeparameter sollte mit jedem Firebird-Client möglich sein, der es dem Benutzer erlaubt, eigene DSQL-Anweisungen einzugeben.Wenn es Eingabeparameter gibt, wird es schwieriger: Diese Parameter müssen ihre Werte erhalten, nachdem die Anweisung vorbereitet wurde, aber bevor sie ausgeführt wird.Dies erfordert besondere Vorkehrungen, die nicht jede Client-Anwendung bietet.(Firebirds eigenes isql zum Beispiel nicht.)
Der Server akzeptiert nur Fragezeichen (“?
”) als Platzhalter für die Eingabewerte, nicht “:a
”, “:MyParam
” etc., oder wörtliche Werte.Client-Software unterstützt jedoch möglicherweise das Formular “:xxx
” und wird es vorverarbeiten, bevor es an den Server gesendet wird.
Wenn der Block Ausgangsparameter hat, muss Sie SUSPEND
verwenden, sonst wird nichts zurückgegeben.
Die Ausgabe wird immer in Form einer Ergebnismenge zurückgegeben, genau wie bei einer SELECT
-Anweisung.Sie können RETURNING_VALUES
nicht verwenden oder den Block INTO
einige Variablen ausführen, selbst wenn es nur eine Ergebniszeile gibt.
Weitere Informationen zum Schreiben von PSQL finden Sie in Kapitel Procedural SQL (PSQL)-Anweisungen.
Einige Editoren für SQL-Anweisungen – insbesondere das Dienstprogramm isql, das mit Firebird geliefert wird, und möglicherweise einige Editoren von Drittanbietern – verwenden eine interne Konvention, die erfordert, dass alle Anweisungen mit einem Semikolon abgeschlossen werden.Dies führt beim Codieren in diesen Umgebungen zu einem Konflikt mit der PSQL-Syntax.Wenn Sie dieses Problem und seine Lösung nicht kennen, lesen Sie bitte die Details im PSQL-Kapitel im Abschnitt Terminator in isql umschalten.