Mam aplikację, w której znajduję sumę() kolumny bazy danych dla zestawu rekordów, a następnie używam tej sumy w oddzielnym zapytaniu, podobnie do następującego (ułożone tabele, ale idea jest taka sama):Dlaczego nie można użyć opcji WYBIERZ ... DO AKTUALIZACJI z funkcjami zagregowanymi?
SELECT Sum(cost)
INTO v_cost_total
FROM materials
WHERE material_id >=0
AND material_id <= 10;
[a little bit of interim work]
SELECT material_id, cost/v_cost_total
INTO v_material_id_collection, v_pct_collection
FROM materials
WHERE material_id >=0
AND material_id <= 10
FOR UPDATE;
Jednak teoretycznie ktoś mógłby zaktualizować kolumnę kosztów w tabeli materiałów między dwoma zapytaniami, w którym to przypadku wyliczone procenty będą wyłączone.
Idealnie, chciałbym po prostu użyć klauzuli FOR UPDATE na pierwszej kwerendy, ale gdy próbuję że pojawia się błąd:
ORA-01786: FOR UPDATE of this query expression is not allowed
Teraz obejście nie jest problem - po prostu wykonaj dodatkową kwerendę, aby zablokować wiersze przed znalezieniem Sum(), ale zapytanie to nie będzie służyć do innych celów niż blokowanie tabel. Chociaż ten konkretny przykład nie jest czasochłonny, dodatkowe zapytanie może spowodować działanie w określonych sytuacjach i nie jest tak czyste, więc chciałbym tego uniknąć.
Czy ktoś zna konkretny powód, dla którego nie jest to dozwolone? W mojej głowie klauzula FOR UPDATE powinna po prostu blokować wiersze pasujące do klauzuli WHERE - nie widzę powodu, dla którego ma znaczenie to, co robimy z tymi wierszami.
EDYCJA: Wygląda na to, że SELECT ... FOR UPDATE może być używany z funkcjami analitycznymi, jak sugeruje David Aldridge poniżej. Oto skrypt testowy, który udowodniłem, że to działa.
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;
/
co daje wynik:
1 10 130
2 30 130
3 90 130
Czy można użyć funkcji analitycznej (suma lub ratio_to_report) za pomocą opcji "wybierz ... do aktualizacji"? Nie mam obecnie dostępnej bazy danych, aby to przetestować, więc nie wiem ... –