UPSERTとINSERTについて
Posted: 2011年6月10日(金) 11:45
データを新規にDBに登録する時に悩むのが、既に同じデータがあったら更新して欲しい。
ですよね。
普通は、それなりの関数を書く必要がありますがOracleは専用の命令がある所が凄いです。
【MERGE】とその凄さについて軽く説明しておきます。
まず、【MERGE】の書式はこうです。
MERGE INTO 表名1
USING 表名2 | 副問い合わせ
ON ( 結合条件 )
WHEN MATCHED THEN
UPDATE SET 列名1 = 値1, 列名2 = 値2, ・・・
WHEN NOT MATCHED THEN
INSERT [( 列名1, 列名2, ・・・ )] VALUES ( 値1, 値2, ・・・ )
で、こんなテーブルを用意しちゃったりします。
ID TEXT DATE
---------- ------------------------------ --------
1 AAAA 08-07-03
2 BBBB 08-07-03
3 CCCC 08-07-03
1.上記のテーブルに対して、DDDDをインサートしてみましょう。
MERGE INTO TEST01
USING DUAL
ON (ID=4)
WHEN MATCHED THEN
UPDATE SET TEXT='DDDD'
WHEN NOT MATCHED THEN
INSERT ( ID, TEXT ) VALUES ( 4,'DDDD' )
;
こんな結果になりました。
ID TEXT DATE
---------- ------------------------------ --------
1 AAAA 08-07-03
2 BBBB 08-07-03
3 CCCC 08-07-03
4 DDDD 08-07-03
2.上記のテーブルに対して、ID=3、TEXT=DDDDを更新してみましょう。
MERGE INTO TEST01
USING DUAL
ON (ID=3)
WHEN MATCHED THEN
UPDATE SET TEXT='DDDD'
WHEN NOT MATCHED THEN
INSERT ( ID, TEXT ) VALUES ( 3,'DDDD' )
;
で、こうなります。
ID TEXT DATE
---------- ------------------------------ --------
1 AAAA 08-07-03
2 BBBB 08-07-03
3 DDDD 08-07-03
バインド変数を使うと更にこんな構文に。
DECLARE
id NUMBER;
text VARCHAR(30);
u_cur INTEGER;
u_sql VARCHAR2(1000);
u_row INTEGER;
BEGIN
id := 4;
text := 'DDDD';
u_cur := DBMS_SQL.OPEN_CURSOR;
u_sql := 'MERGE INTO TEST01 USING DUAL ON (ID=:b1) WHEN MATCHED THEN UPDATE SET TEXT=:b2 WHEN NOT MATCHED THEN INSERT ( ID, TEXT ) VALUES ( :b1, :b2 )';
DBMS_SQL.PARSE(u_cur, u_sql, dbms_sql.v7);
DBMS_SQL.BIND_VARIABLE(u_cur, ':b1', id);
DBMS_SQL.BIND_VARIABLE(u_cur, ':b2', text);
u_row := DBMS_SQL.EXECUTE(u_cur);
DBMS_SQL.CLOSE_CURSOR(u_cur);
End
;
/
・・・なりました。
ですよね。
普通は、それなりの関数を書く必要がありますがOracleは専用の命令がある所が凄いです。
【MERGE】とその凄さについて軽く説明しておきます。
まず、【MERGE】の書式はこうです。
MERGE INTO 表名1
USING 表名2 | 副問い合わせ
ON ( 結合条件 )
WHEN MATCHED THEN
UPDATE SET 列名1 = 値1, 列名2 = 値2, ・・・
WHEN NOT MATCHED THEN
INSERT [( 列名1, 列名2, ・・・ )] VALUES ( 値1, 値2, ・・・ )
で、こんなテーブルを用意しちゃったりします。
ID TEXT DATE
---------- ------------------------------ --------
1 AAAA 08-07-03
2 BBBB 08-07-03
3 CCCC 08-07-03
1.上記のテーブルに対して、DDDDをインサートしてみましょう。
MERGE INTO TEST01
USING DUAL
ON (ID=4)
WHEN MATCHED THEN
UPDATE SET TEXT='DDDD'
WHEN NOT MATCHED THEN
INSERT ( ID, TEXT ) VALUES ( 4,'DDDD' )
;
こんな結果になりました。
ID TEXT DATE
---------- ------------------------------ --------
1 AAAA 08-07-03
2 BBBB 08-07-03
3 CCCC 08-07-03
4 DDDD 08-07-03
2.上記のテーブルに対して、ID=3、TEXT=DDDDを更新してみましょう。
MERGE INTO TEST01
USING DUAL
ON (ID=3)
WHEN MATCHED THEN
UPDATE SET TEXT='DDDD'
WHEN NOT MATCHED THEN
INSERT ( ID, TEXT ) VALUES ( 3,'DDDD' )
;
で、こうなります。
ID TEXT DATE
---------- ------------------------------ --------
1 AAAA 08-07-03
2 BBBB 08-07-03
3 DDDD 08-07-03
バインド変数を使うと更にこんな構文に。
DECLARE
id NUMBER;
text VARCHAR(30);
u_cur INTEGER;
u_sql VARCHAR2(1000);
u_row INTEGER;
BEGIN
id := 4;
text := 'DDDD';
u_cur := DBMS_SQL.OPEN_CURSOR;
u_sql := 'MERGE INTO TEST01 USING DUAL ON (ID=:b1) WHEN MATCHED THEN UPDATE SET TEXT=:b2 WHEN NOT MATCHED THEN INSERT ( ID, TEXT ) VALUES ( :b1, :b2 )';
DBMS_SQL.PARSE(u_cur, u_sql, dbms_sql.v7);
DBMS_SQL.BIND_VARIABLE(u_cur, ':b1', id);
DBMS_SQL.BIND_VARIABLE(u_cur, ':b2', text);
u_row := DBMS_SQL.EXECUTE(u_cur);
DBMS_SQL.CLOSE_CURSOR(u_cur);
End
;
/
・・・なりました。