我有一个应用程序,在该应用程序中,我对一组记录的数据库列执行Sum()操作,并在稍后使用该总和进行单独的查询,类似于以下示例(虚构的表,但思想相同):
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;
然而,从理论上讲,有人可能会在两个查询之间更新材料表的成本列,在这种情况下,计算出的百分比将不准确。
理想情况下,我只想在第一个查询上使用FOR UPDATE子句,但是当我尝试时,我会收到错误提示:
ORA-01786: FOR UPDATE of this query expression is not allowed
现在,解决方法并不是问题——只需在查找Sum()之前执行额外的查询以锁定行即可,但是该查询除了锁定表格外没有任何其他用途。虽然这个特定的例子并不费时,但在某些情况下,额外的查询可能会导致性能损失,并且它不太干净,所以我想避免这样做。
有人知道为什么不允许这样做吗?在我的脑海中,“FOR UPDATE”子句应该只锁定与“WHERE”子句匹配的行——我不明白为什么在处理这些行时要注意什么。
编辑:看起来可以像David Aldridge建议的那样使用SELECT ... FOR UPDATE与分析函数。这是我用来证明这个方法有效的测试脚本。
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;
/
这将生成输出:
1 10 130
2 30 130
3 90 130