マージを使用しようとしていますが、次のエラーが表示されます
ORA-00928: SELECT キーワードがありません
merge into table using(select * from table on val = val1)
when matched then
(update set
val2 = val3 where val = val1)
when not matched then
(Insert query)
私は何を取りこぼしたか?
構文は非常に規範的です。一致基準は別の ON 句に属し、括弧で囲む必要があります。 詳細をご覧ください。
SQL> merge into t23 tgt
2 using ( select * from t23 ) q
3 on (tgt.col1 = q.col1)
4 when not matched then
5 insert values (q.col1, q.id+20, q.col2, q.date_time, q.qty, q.dt)
6 when matched then
7 update set tgt.col2 = q.col2 * 2
8 /
4 rows merged.
SQL>
「どこでも同じテーブルを使用していますが、それが問題でしょうか?」
いいえ。クエリの例が示すように、MERGE はソースおよびターゲットと同じテーブルで実行できます。しかし、問題は、なぜそれをやりたいのかということです。すべての行が一致する場合は を実行するupdate
か、一致しない場合はinsert ... select from
.
疑似クエリをもう一度見てみると、何をしようとしているのかがわかると思います。秘訣は、ON 句の条件がターゲット セットの 1 つの行と USING セットの 1 つの行に一致するようにすることです。そうでなければ、それは投げますORA-30926: unable to get a stable set of rows in the source tables
そこで、以前のクエリを再加工したバージョンを次に示します。
開始データ・セット (USING セット):
SQL> select id, col1, qty, col2 from t23;
ID COL1 QTY C
------------------------------ ---------- ---------- -
ABCD0001 5 100 N
ABCD0002 10 10 N
ABCD0003 15 20 N
ABCD0004 20 -30 N
ABCD0005 35 20 N
ABCD0006 25 100 N
ABCD0007 30 30 N
ABCD0008 40 -30 N
8 rows selected.
SQL>
ON 条件は、安定したセットを保証するために 2 つの列を結合します。
SQL> merge into t23 tgt
2 using ( select * from t23 ) q
3 on (tgt.id = q.id
4 and tgt.col1 = tgt.qty)
5 when not matched then
6 insert values (q.id, q.col1+20, 'X', q.date_time, q.qty, q.dt)
7 when matched then
8 update set tgt.col2 = 'Y'
9 /
8 rows merged.
SQL>
結果は、2 回の更新と 6 回の挿入です...
SQL> select id, col1, qty, col2 from t23;
ID COL1 QTY C
------------------------------ ---------- ---------- -
ABCD0001 5 100 N
ABCD0002 10 10 Y
ABCD0003 15 20 N
ABCD0004 20 -30 N
ABCD0005 35 20 N
ABCD0006 25 100 N
ABCD0007 30 30 Y
ABCD0008 40 -30 N
ABCD0008 60 -30 X
ABCD0004 40 -30 X
ABCD0001 25 100 X
ABCD0003 35 20 X
ABCD0006 45 100 X
ABCD0005 55 20 X
14 rows selected.
SQL>
この戦術の明らかな危険は、主キーの衝突です。私のテーブルはバガテルで、主キーがありません。実際には、テーブルには主キーが必要であり、INSERT 句でそれを処理する必要があります。
興味深いことに、UPDATE 分岐の WHERE 句は有効な構文です (ただし、OP の例では、ON 基準が重複しているため冗長です)。元のデータ セットに対してこの MERGE を実行すると、6 行がマージされます (6 回の挿入、更新なし)。
merge into t23 tgt
using ( select * from t23 ) q
on (tgt.id = q.id
and tgt.col1 = tgt.qty)
when not matched then
insert values (q.id, q.col1+20, 'X', q.date_time, q.qty, q.dt)
when matched then
update set tgt.col2 = 'Y'
where tgt.col2 = 'Z'
/
WHERE 句は MATCHED 分岐にのみ適用され、一致した行を更新または削除するかどうかを決定するために使用されます。
結合条件が間違っています:
merge into table using (
select * from table
) on val = val1 --<< needs to go outside of the sub-select
when matched then
(update set
val2 = val3 where val = val1)
when not matched then
(Insert query)