Die UPDATE-Anweisung gibt die zu ändernden Zeilen an sowie die Ausdrücke, die als neue Werte für bestimmte Spalten in diesen Zeilen verwendet werden sollen.
Sie können die UPDATE-Anweisung verwenden, um einzelne Zeilen, Gruppen von Zeilen oder alle Zeilen in einer Tabelle zu ändern. Im Gegensatz zu anderen Datenmanipulationsanweisungen (INSERT, MERGE und DELETE) können Sie mit der UPDATE-Anweisung auch Zeilen in mehreren Tabellen gleichzeitig ändern. In allen Fällen ist die Ausführung der UPDATE-Anweisung atomar, d.h., entweder werden alle Zeilen ohne Fehler geändert oder keine von ihnen. Wenn beispielsweise einer der zu ändernden Werte den falschen Datentyp hat oder wenn der neue Wert bewirkt, dass eine CHECK-Integritätsregel verletzt wird, schlägt die UPDATE-Anweisung fehl und der gesamte Vorgang wird zurückgesetzt.
Eine vereinfachte Version der Syntax für die UPDATE-Anweisung lautet wie folgt:
UPDATE table-name SET column_name = expression WHERE search-condition
Wenn das Unternehmen Newton Ent. (in der Tabelle "Customers" der SQL Anywhere-Beispieldatenbank) von Einstein, Inc. übernommen wird, können Sie den Namen des Unternehmens mithilfe folgender Anweisung aktualisieren:
UPDATE Customers SET CompanyName = 'Einstein, Inc.' WHERE CompanyName = 'Newton Ent.'; |
Sie können in einer WHERE-Klausel jeden beliebigen Ausdruck verwenden. Wenn Sie nicht sicher sind, wie der Firmenname geschrieben wird, können Sie alle Firmen mit dem Namen "Newton" aktualisieren.Hierzu können Sie z.B. folgende Anweisung verwenden:
UPDATE Customers SET CompanyName = 'Einstein, Inc.' WHERE CompanyName LIKE 'Newton%'; |
Die Suchbedingung muss sich nicht auf die zu aktualisierende Spalte beziehen. Die Unternehmenskennung für Newton Entertainments ist 109. Da diese Kennung der Primärschlüssel für die Tabelle ist, können Sie sicher sein, dass die richtige Zeile aktualisiert wird, indem Sie folgende Anweisung verwenden:
UPDATE Customers SET CompanyName = 'Einstein, Inc.' WHERE ID = 109; |
Sie können auch Zeilen der Ergebnismenge in Interactive SQL ändern.
Die SET-Klausel gibt an, welche Spalten aktualisiert werden müssen und wie deren neue Werte lauten. Die WHERE-Klausel legt die Zeilen fest, die aktualisiert werden müssen. Wenn Sie keine WHERE-Klausel eingeben, werden die angegebenen Spalten aller Zeilen mit den Werten aktualisiert, die in der SET-Klausel eingegeben wurden.
Die in der SET-Klausel angegebenen Ausdrücke können Literalkonstanten, Host- oder SQL-Variablen, Unterabfragen, Spezialwerte wie CURRENT TIMESTAMP, aus einer anderen Tabelle übernommene Ausdruckswerte oder eine beliebige Kombination dieser Elemente sein. Sie können in einer SET-Klausel auch DEFAULT angeben, was für den Standardwert der betreffenden Spalte in der Basistabelle steht. Wenn sich der Datentyp des Ausdrucks vom Datentyp der zu ändernden Spalte unterscheidet, wird der Ausdruck vom Datenbankserver, sofern möglich, automatisch in den Datentyp der Spalte konvertiert. Wenn die Konvertierung nicht möglich ist, resultiert eine Datenausnahmebedingung und die UPDATE-Anweisung schlägt fehl.
Sie können die SET-Klausel verwenden, um zusätzlich zum Ändern von Spaltenwerten den Wert für eine Variable festzulegen. In diesem Beispiel wird zusätzlich zum Aktualisieren der Tabelle "T" der Variablen @var ein Wert zugeordnet:
UPDATE T SET @var = expression1, col1 = expression2 WHERE...; |
Dies entspricht ungefähr dem seriellen Ausführen einer SELECT-Anweisung, gefolgt von einer UPDATE-Anweisung:
SELECT @var = expression1 FROM T WHERE... ; UPDATE T SET col1 = expression2 WHERE...; |
Der Vorteil der Variablenzuordnung innerhalb einer UPDATE-Anweisung besteht darin, dass der Wert der Variablen noch während der Ausführung der Anweisung festgelegt werden kann, solange diese Schreibsperren besitzt. Dadurch wird verhindert, dass durch parallele Aktualisierungsaktivitäten anderer Verbindungen unerwartete Werte zugeordnet werden.
Die WHERE-Klausel gibt an, welche Zeilen aktualisiert werden sollen, indem search-condition auf die Tabelle oder das kartesische Produkt aus Tabellenausdrücken in der UPDATE-Anweisung angewendet wird. Die folgende Anweisung ersetzt beispielsweise das T-Shirt der Größe "One Size Fits All" durch ein T-Shirt der Größe "Extra Large":
UPDATE Products SET Size = 'Extra Large' WHERE Name = 'Tee Shirt' AND Size = 'One Size Fits All'; |
Komplexere Formen der UPDATE-Anweisung ermöglichen Aktualisierungen über Joins und andere Arten von Tabellenausdrücken hinweg.
Syntax 1 der UPDATE-Anweisung lautet beispielsweise:
UPDATE [ row-limitation ] table-name SET set-item[, ...] FROM table-expression [, ...] ] [ WHERE search-condition ] [ ORDER BY expression [ ASC | DESC ] , ...] [ OPTION( query-hint, ... ) ]
Die Semantik dieser Form der UPDATE-Anweisung besteht darin, dass zunächst eine Ergebnismenge berechnet wird, die aus allen Kombinationen von Zeilen aus jedem table-expression besteht, anschließend die search-condition in der WHERE-Klausel angewendet wird und schließlich die resultierenden Zeilen mit der ORDER BY-Klausel sortiert werden. Aus dieser Berechnung ergibt sich die Menge der Zeilen, die geändert werden. Jeder table-expression kann aus Joins von Basistabellen, Ansichten und abgeleiteten Tabellen bestehen. Die Syntax erlaubt es, eine oder mehrere Tabellen mit Werten aus Spalten in anderen Tabellen zu aktualisieren. Der Abfrageoptimierer ändert möglicherweise die Reihenfolge der Vorgänge, um eine effizientere Ausführungsstrategie für die UPDATE-Anweisung zu erstellen.
Wenn eine Basistabelle in einer Menge von mehrmals zu ändernden Zeilen erscheint, wird die Zeile mehrfach aktualisiert, sofern sich die neuen Werte bei jedem Manipulationsversuch unterscheiden. Wenn ein BEFORE ROW UPDATE-Trigger vorhanden ist, wird der BEFORE ROW UPDATE-Trigger für jede einzelne Zeilenmanipulation ausgelöst, gemäß der UPDATE OF column-list-Klausel des Triggers. AFTER ROW UPDATE-Trigger werden ebenfalls für jede einzelne Zeilenmanipulation ausgelöst, jedoch nur, wenn die Werte der Zeile tatsächlich geändert werden, gemäß der UPDATE OF column-list-Klausel des Triggers.
Trigger werden für jede aktualisierte Tabelle ausgelöst, basierend auf dem Typ des Triggers und dem Wert der ORDER-Klausel für jede Triggerdefinition. Wenn eine UPDATE-Anweisung mehr als eine Tabelle ändert, ist jedoch die Reihenfolge, in der die Tabellen aktualisiert werden, nicht gewährleistet.
Im folgenden Beispiel werden ein BEFORE ROW UPDATE-Trigger und ein AFTER STATEMENT UPDATE-Trigger in der Products-Tabelle erstellt, die jeweils eine Meldung im Meldungsfenster des Datenbankservers ausgeben:
CREATE OR REPLACE TRIGGER trigger0 BEFORE UPDATE ON Products REFERENCING OLD AS old_product NEW AS new_product FOR EACH ROW BEGIN PRINT ('BEFORE row: PK value: ' || old_product.ID || ' New Price: ' || new_product.UnitPrice ); END; CREATE OR REPLACE TRIGGER trigger1 AFTER UPDATE ON Products REFERENCING NEW AS new_product FOR EACH STATEMENT BEGIN DECLARE @pk INTEGER; DECLARE @newUnitPrice DECIMAL(12,2); DECLARE @err_notfound EXCEPTION FOR SQLSTATE VALUE '02000'; DECLARE new_curs CURSOR FOR SELECT ID, UnitPrice FROM new_product; OPEN new_curs; LoopGetRow: LOOP FETCH NEXT new_curs INTO @pk, @newUnitPrice; IF SQLSTATE = @err_notfound THEN LEAVE LoopGetRow END IF; PRINT ('AFTER stmt: PK value: ' || @pk || ' Unit price: ' || @newUnitPrice ); END LOOP LoopGetRow; CLOSE new_curs END; |
Angenommen, Sie führen anschließend eine UPDATE-Anweisung über einen Join der Products-Tabelle mit der SalesOrderItems-Tabelle aus, um einen Rabatt von 5 % auf Produkte anzuwenden, die seit dem 1. April 001 versandt wurden und für die mindestens ein großer Auftrag vorliegt:
UPDATE Products p JOIN SalesOrderItems s ON (p.ID = s.ProductID) SET p.UnitPrice = p.UnitPrice * 0.95 WHERE s.ShipDate > '2001-04-01' AND s.Quantity >= 72; |
Das Meldungsfenster des Datenbankservers zeigt die folgenden Meldungen:
BEFORE row: PK value: 700 New Price: 14.25 BEFORE row: PK value: 302 New Price: 13.30 BEFORE row: PK value: 700 New Price: 13.54 AFTER stmt: PK value: 700 Unit price: 14.25 AFTER stmt: PK value: 302 Unit price: 13.30 AFTER stmt: PK value: 700 Unit price: 13.54 |
Die Meldungen zeigen, dass Produkt 700 zweimal aktualisiert wurde, weil es in zwei verschiedenen Aufträgen enthalten war, die die Suchbedingung in der UPDATE-Anweisung erfüllen. Die mehrfach vorhandenen Aktualisierungen sind sowohl für den BEFORE ROW-Trigger als auch für den AFTER STATEMENT-Trigger sichtbar. Bei jeder Zeilenmanipulation werden der alte und der neue Wert für jeden Triggeraufruf entsprechend geändert. Bei einem AFTER STATEMENT-Trigger stimmt die Reihenfolge der Zeilen in den durch die REFERENCING-Klausel gebildeten temporären Tabellen möglicherweise nicht mit der Reihenfolge überein, in der die Zeilen geändert wurden, und die genaue Reihenfolge der Zeilen ist nicht gewährleistet.
Aufgrund der mehrfach vorhandenen Aktualisierungen wurde der Rabatt zweimal auf den UnitPrice-Wert für Produkt 700 angewendet, sodass der Stückpreis von ursprünglich $15.00 auf $13.54 gesenkt wurde (was einem Rabatt von 9,75% entspricht) und nicht nur auf $14.25. Zur Vermeidung dieser unbeabsichtigten Folge können Sie stattdessen die UPDATE-Anweisung so formulieren, dass statt eines Joins eine EXISTS-Unterabfrage verwendet wird, um sicherzustellen, dass jede Produktzeile höchstens einmal geändert wird. Die überarbeitete UPDATE-Anweisung enthält sowohl eine EXISTS-Unterabfrage als auch die alternative Syntax der UPDATE-Anweisung, die eine FROM-Klausel zulässt:
UPDATE Products AS p SET p.UnitPrice = p.UnitPrice * 0.95 FROM Products AS p WHERE EXISTS( SELECT * FROM SalesOrderItems s WHERE p.ID = s.ProductID AND s.ShipDate > '2001-04-01' AND s.Quantity >= 72); |
Wenn eine UPDATE-Anweisung während der Ausführung eine Integritätsregel zur Erhaltung der referenziellen Integrität verletzt, wird das Verhalten der Anweisung durch die Einstellung der wait-for-commit-Option gesteuert. Wenn die wait_for_commit-Option auf OFF gesetzt ist und eine Integritätsregel zur Erhaltung der referenziellen Integrität verletzt wird, werden die Auswirkungen der UPDATE-Anweisung sofort automatisch zurückgesetzt und eine Fehlermeldung wird angezeigt. Wenn die wait_for_commit-Option auf ON gesetzt ist, wird jede durch die UPDATE-Anweisung verursachte Verletzung einer Integritätsregel zur Erhaltung der referenziellen Integrität vorübergehend ignoriert und später überprüft, wenn die Verbindung eine COMMIT-Anweisung ausführt.
Wenn die Basistabelle oder zu ändernde Tabellen Primärschlüssel, UNIQUE-Integritätsregeln oder eindeutige Indizes enthalten, kann eine zeilenweise Ausführung der UPDATE-Anweisung dazu führen, dass eine Eindeutigkeits-Integritätsregel verletzt wird. Sie können beispielsweise eine UPDATE-Anweisung ausgeben, die die Werte aller Primärschlüsselspalten für eine Tabelle "T" inkrementiert:
UPDATE T SET PKcol = PKcol + 1; |
Wenn während der Ausführung einer UPDATE-Anweisung eine Verletzung der Eindeutigkeit auftritt, führt der Datenbankserver automatisch die folgenden Schritte aus:
Alter und neuer Wert der geänderten Zeile werden in eine temporäre Tabelle mit demselben Schema wie die zu ändernde Basistabelle kopiert.
Die ursprüngliche Zeile wird aus der Basistabelle gelöscht. Als Folge dieses Löschvorgangs werden keine DELETE-Trigger ausgelöst.
Während der Ausführung der UPDATE-Anweisung hängt es von der Reihenfolge der Auswertung ab, welche Zeilen erfolgreich aktualisiert und welche vorübergehend gelöscht werden, und dies kann nicht gewährleistet werden. Das Verhalten von SQL-Anforderungen von anderen Verbindungen, die auf schwächeren Isolationsstufen (Isolationsstufe 0, 1 oder 2) ausgeführt werden, kann durch diese vorübergehend gelöschten Zeilen beeinflusst werden. An alle BEFORE ROW- oder AFTER ROW-Trigger der geänderten Tabelle werden die alten und neuen Werte der einzelnen Zeilen gemäß der REFERENCING-Klausel des Triggers übergeben, aber wenn der ROW-Trigger eine separate SQL-Anweisung in der geänderten Tabelle ausgibt, fehlen die in der temporären Tabelle gespeicherten Zeilen.
Nachdem die UPDATE-Anweisung die Änderungen an jeder Zeile abgeschlossen hat, werden die in der temporären Tabelle gespeicherten Zeilen wieder in die Basistabelle eingefügt. Wenn weiterhin eine Verletzung der Eindeutigkeit auftritt, wird die gesamte UPDATE-Anweisung zurückgesetzt. Erst wenn alle in der temporären Tabelle gespeicherten Zeilen erfolgreich wieder in die Basistabelle eingefügt wurden, werden AFTER STATEMENT-Trigger ausgelöst.
Der Datenbankserver verwendet keine Haltetabelle zum temporären Speichern von Zeilen, wenn die zu ändernde Basistabelle das Ziel einer durch eine Integritätsregel zur Erhaltung der referenziellen Integrität ausgelösten Aktion ist, einschließlich ON DELETE CASCADE, ON DELETE SET NULL, ON DELETE DEFAULT, ON UPDATE CASCADE, ON UPDATE SET NULL und ON UPDATE DEFAULT.
![]() |
Kommentieren Sie diese Seite in DocCommentXchange.
|
Copyright © 2013, SAP AG oder ein SAP-Konzernunternehmen. - SAP Sybase SQL Anywhere 16.0 |