我有一个应用程序,我找到一组记录的数据库列的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子句匹配的行 - 我不明白为什么我们对这些行的处理很重要。
编辑:看起来像SELECT ... FOR UPDATE可以与分析函数一起使用,如下面的David Aldridge所建议的那样。这是我用来证明这个工作的测试脚本。
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
答案 0 :(得分:19)
语法select . . . for update
锁定表中的记录以准备更新。进行聚合时,结果集不再引用原始行。
换句话说,数据库中没有要更新的记录。只有一个临时结果集。
答案 1 :(得分:3)
您可以尝试以下方式:
<<LOCAL>>
declare
material_id materials.material_id%Type;
cost materials.cost%Type;
total_cost materials.cost%Type;
begin
select material_id,
cost,
sum(cost) over () total_cost
into local.material_id,
local.cost,
local.total_cost
from materials
where material_id between 1 and 3
for update of cost;
...
end local;
第一行为您提供总费用,但它会选择所有行,理论上它们可能会被锁定。
我不知道这是否被允许,请注意 - 听听它是否有趣。
答案 2 :(得分:1)
为此,您可以使用 WITH
命令。
示例:
WITH result AS (
-- your select
) SELECT * FROM result GROUP BY material_id;
答案 3 :(得分:0)
你的问题“但是,理论上有人可以在两个查询之间更新材料表上的成本列,在这种情况下,计算的百分比将会关闭。”?
在这种情况下,您可以简单地使用内部查询:
SELECT material_id, cost/(SELECT Sum(cost)
FROM materials
WHERE material_id >=0
AND material_id <= 10)
INTO v_material_id_collection, v_pct_collection
FROM materials
WHERE material_id >=0
AND material_id <= 10;
为什么要锁定表格?如果他们在那段时间内尝试更新该表,其他应用程序可能会失败吗?