16

一連のレコードのデータベース列の 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; 

ただし、理論的には、誰かが 2 つのクエリの間に材料テーブルのコスト列を更新することができます。その場合、計算されたパーセントはずれます。

理想的には、最初のクエリで FOR UPDATE 句を使用するだけですが、それを試みるとエラーが発生します。

ORA-01786: FOR UPDATE of this query expression is not allowed

ここで、回避策は問題ではありません。Sum() を見つける前に追加のクエリを実行して行をロックするだけですが、そのクエリはテーブルをロックする以外の目的にはなりません。この特定の例は時間がかかるものではありませんが、余分なクエリが特定の状況でパフォーマンス ヒットを引き起こす可能性があり、クリーンではないため、それを行う必要は避けたいと考えています。

これが許可されていない特定の理由を知っている人はいますか? 私の頭の中では、FOR UPDATE 句は WHERE 句に一致する行をロックするだけでよいと考えています。これらの行をどう処理するかが重要な理由がわかりません。

EDIT:以下の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
4

4 に答える 4