Ho un'applicazione in cui trovo una sum() di una colonna del database per un set di record e successivamente la uso in una query separata, simile alla seguente (tabelle composte, ma l'idea è la stessa):Perché non posso usare SELECT ... FOR UPDATE con funzioni di aggregazione?
Tuttavia, in teoria qualcuno potrebbe aggiornare la colonna dei costi nella tabella dei materiali tra le due query, nel qual caso le percentuali calcolate saranno spente.
Idealmente, vorrei solo usare una clausola FOR UPDATE sulla prima query, ma quando provo che, ottengo un errore:
ORA-01786: FOR UPDATE of this query expression is not allowed
Ora, il work-around non è il problema - solo fai una query aggiuntiva per bloccare le righe prima di trovare Sum(), ma quella query non servirebbe altro che il blocco delle tabelle. Anche se questo particolare esempio non richiede molto tempo, la query aggiuntiva potrebbe causare un problema di prestazioni in determinate situazioni e non è così pulita, quindi mi piacerebbe evitare di doverlo fare.
Qualcuno sa di un motivo particolare per cui questo non è consentito? Nella mia testa, la clausola FOR UPDATE dovrebbe semplicemente bloccare le righe che corrispondono alla clausola WHERE - Non vedo perché è importante quello che stiamo facendo con quelle righe.
MODIFICA: Sembra che SELECT ... FOR UPDATE possa essere utilizzato con le funzioni analitiche, come suggerito da David Aldridge di seguito. Ecco lo script di test che ho usato per dimostrare che funziona.
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;
/
che fornisce l'output:
1 10 130
2 30 130
3 90 130
È possibile utilizzare una funzione analitica (somma o rapporto_port_) con 'selezionare ... per l'aggiornamento'? Non ho un database disponibile al momento per testarlo, quindi non so ... –