まず、テーブルと背景を設定するためのスクリプトをいくつか示します。Oracleのロックと集約についての質問
CREATE TABLE TEST_P
(
ID NUMBER(3) NOT NULL PRIMARY KEY,
SRC VARCHAR2(2) NOT NULL,
DEST VARCHAR2(2) NOT NULL,
AMT NUMBER(4) NOT NULL,
B_ID_SRC NUMBER(3),
B_ID_DEST NUMBER(3)
);
この表の行は、AMTがSRC
からDEST
に移動されていることを示します。 ID
列は代理キーです。最初の行は、10個の物がB1からS1に移動していることを示しています。 SRC
とDEST
の値は異なります。両方に同じ値を表示することはできません。
INSERT INTO TEST_P VALUES (1, 'B1', 'S1', 10, NULL, NULL);
INSERT INTO TEST_P VALUES (2, 'B2', 'S1', 20, NULL, NULL);
INSERT INTO TEST_P VALUES (3, 'B3', 'S2', 40, NULL, NULL);
INSERT INTO TEST_P VALUES (4, 'B1', 'S2', 80, NULL, NULL);
INSERT INTO TEST_P VALUES (5, 'B4', 'S2', 160,NULL, NULL);
このような別のテーブルがあります。それは同じ情報の異なる見解を持っています。ここの各行は、「Who」に追加または削除されたものを示しています。値は、B1、B2 ...とS1、S2 ...定期的にTEST_P
から値を取得し、TEST_B
に移入されますプロセスを記述する必要は
CREATE TABLE TEST_B
(
ID NUMBER(3) NOT NULL PRIMARY KEY,
BATCH NUMBER(3) NOT NULL,
WHO VARCHAR2(2) NOT NULL,
AMT NUMBER(4) NOT NULL
);
CREATE SEQUENCE TEST_B_SEQ START WITH 100;
です。また、外部キーである B_ID_SRC
とB_ID_DEST
をTEST_B
に更新する必要があります。
これまでのところ私の解決策です。
ステップ1:
INSERT INTO TEST_B
(ID, BATCH, WHO, AMT)
SELECT TEST_B_SEQ.NEXTVAL, 42, WHO, AMT FROM
(
SELECT SRC AS WHO, SUM(AMT) AMT FROM TEST_P
WHERE B_ID_SRC IS NULL AND B_ID_DEST IS NULL
GROUP BY SRC
UNION ALL
SELECT DEST, -SUM(AMT) FROM TEST_P
WHERE B_ID_SRC IS NULL AND B_ID_DEST IS NULL
GROUP BY DEST)
;
ステップ2:
1)SELECTの行がロックされるべきである:
UPDATE TEST_P
SET B_ID_SRC = (SELECT ID FROM TEST_B WHERE BATCH = 42 AND TEST_P.SRC = WHO),
B_ID_DEST = (SELECT ID FROM TEST_B WHERE BATCH = 42 AND TEST_P.DEST = WHO);
これには二つの問題があります。 FOR UPDATE
でこの選択を行うにはどうすればよいですか?
2)行が別のセッションによって挿入され、ステップ1.5でコミットされた場合、UPDATEはINSERTより多くの行を取得します。行ごとの処理に戻さずにこれを解決するにはどうすればよいですか?
詳細 実際のTEST_P
テーブルにはステータスカラムがあります。物事が正しい状態にあるときだけ、それはTEST_B
に含まれます。
実際にはTEST_B
が必要です。私はそれをただのものにすることはできません。その後の処理などがあります。TEST_P
のすべての行を更新する場合は、
ありがとう、ヴィンセント、これは私が必要なものです。実際には、テーブル全体をロックすることはできません。そこには他のものがないからです。シリアライズ可能なトランザクションが必要です。 –