Ich habe eine Anwendung, wo ich eine sum() einer Datenbankspalte für eine Reihe von Datensätzen finden und später diese Summe in einer separaten Abfrage, ähnlich der folgenden (erfundenen Tabellen, aber die Idee ist die gleiche):Warum kann ich SELECT ... FOR UPDATE nicht mit Aggregatfunktionen verwenden?
Theoretisch könnte jedoch jemand die Kostenspalte in der Materialtabelle zwischen den beiden Abfragen aktualisieren, in diesem Fall sind die berechneten Prozente ausgeschalten.
Im Idealfall würde ich nur auf der ersten Abfrage FOR UPDATE-Klausel verwenden, aber wenn ich versuche, dass, erhalte ich eine Fehlermeldung:
ORA-01786: FOR UPDATE of this query expression is not allowed
Nun wird die Work-around ist nicht das Problem - einfach Führen Sie eine zusätzliche Abfrage durch, um die Zeilen zu sperren, bevor Sie die Summe() finden. Diese Abfrage würde jedoch keinen anderen Zweck als das Sperren der Tabellen erfüllen. Während dieses spezielle Beispiel nicht zeitaufwendig ist, könnte die zusätzliche Abfrage in bestimmten Situationen einen Leistungseinbruch verursachen und ist nicht so sauber. Daher möchte ich es vermeiden, dies zu tun.
Kennt jemand einen bestimmten Grund, warum dies nicht erlaubt ist? In meinem Kopf sollte die FOR UPDATE-Klausel nur die Zeilen sperren, die der WHERE-Klausel entsprechen. Ich sehe nicht, warum es wichtig ist, was wir mit diesen Zeilen machen.
EDIT: Es sieht aus wie SELECT ... FOR UPDATE kann mit analytischen Funktionen verwendet werden, wie von David Aldridge unten vorgeschlagen. Hier ist das Testskript, mit dem ich bewiesen habe, dass es funktioniert.
SET serveroutput ON;
CREATE TABLE materials (
material_id NUMBER(10,0),
cost NUMBER(10,2)
);
ALTER TABLE materials ADD PRIMARY KEY (material_id);
INSERT INTO materials VALUES (1,10);
INSERT INTO materials VALUES (2,30);
INSERT INTO materials VALUES (3,90);
<<LOCAL>>
DECLARE
l_material_id materials.material_id%TYPE;
l_cost materials.cost%TYPE;
l_total_cost materials.cost%TYPE;
CURSOR test IS
SELECT material_id,
cost,
Sum(cost) OVER() total_cost
FROM materials
WHERE material_id BETWEEN 1 AND 3
FOR UPDATE OF cost;
BEGIN
OPEN test;
FETCH test INTO l_material_id, l_cost, l_total_cost;
Dbms_Output.put_line(l_material_id||' '||l_cost||' '||l_total_cost);
FETCH test INTO l_material_id, l_cost, l_total_cost;
Dbms_Output.put_line(l_material_id||' '||l_cost||' '||l_total_cost);
FETCH test INTO l_material_id, l_cost, l_total_cost;
Dbms_Output.put_line(l_material_id||' '||l_cost||' '||l_total_cost);
END LOCAL;
/
, die den Ausgang gibt:
1 10 130
2 30 130
3 90 130
Ist es möglich, eine analytische Funktion (sum oder ratio_to_report) mit 'select ... for update' zu verwenden? Ich habe im Moment keine Datenbank, um das zu testen, weiß also nicht ... –