Oracle ¤Î MERGE ¹½Ê¸¤Ë´Ø¤¹¤ëÈ÷˺Ͽ - ¥Ð¥¤¥ó¥ÉÊÑ¿ô¤Î°·¤¤Êý

DB ¥¢¥×¥ê¤ò½ñ¤¤¤Æ¤¤¤ë¤È¡¢¤É¤¦¤·¤Æ¤â»È¤¤¤¿¤¯¤Ê¤ë¤Î¤¬ UPSERT µ¡Ç½¡£
¼ÂºÝ¤Ë¤Ï UPSERT ¤È¤¤¤¦¹½Ê¸¤Ï¤¢¤ê¤Þ¤»¤ó¤¬¡¢°ÕÌ£¤È¤·¤Æ¤Ï¥ì¥³¡¼¥É¤¬¤¢¤ì¤Ð UPDATE ¤Ç¹¹¿·¤·¡¢¥ì¥³¡¼¥É¤¬¤Ê¤±¤ì¤Ð INSERT ¤ÇÄɲäò¤¹¤ë¤Ã¤Æ¤³¤È¤Ç¤¹¡£
½¾¤Ã¤Æ¡¢ÉáÄ̤˽ñ¤¯¤Ê¤é¡¢SELECT ¢ª UPDATE/INSERT ¤È¾ì¹çʬ¤±¤È¤¤¤¦¥í¥¸¥Ã¥¯¤Ç¥×¥í¥°¥é¥à¤ò½ñ¤¯¤ï¤±¤Ç¤¹¤¬¡¢¥È¥é¥ó¥¶¥¯¥·¥ç¥ó¤Ç¹Í¤¨¤ë¤È¥³¥ì¤¬°Õ³°¤È¤ä¤Ã¤«¤¤¤Ê¤È¤­¤¬¤¢¤ê¤Þ¤¹¡£¤½¤Î¤è¤¦¤Ê¾ì¹ç¤Ï SELECT FOR UPDATE ¤È¤«»È¤Ã¤Æ¹Ô¥í¥Ã¥¯¤ò¤«¤±¤¿¤ê¤¹¤ëÌõ¤Ê¤Î¤Ç¤¹¤¬¡¢¤³¤ì¤Þ¤¿Í½´ü¤»¤Ì¥í¥Ã¥¯ÂÔ¤Á¤Î¸µ¤Ë¤Ê¤Ã¤¿¤ê¤¹¤ë¾ì¹ç¤¬¤¢¤êÆÀ¤ë¤Î¤Ç¡¢¤¢¤Þ¤ê¿Í¤Ë½ñ¤«¤»¤¿¤¯¤Ê¤¤¡£

Oracle ¤Ë¤Ï UPSERT ¤ËÁêÅö¤¹¤ë¹½Ê¸¤È¤·¤Æ MERGE ¹½Ê¸¤¬¤¢¤ë¤Î¤Ç¡¢·ë¹½½ÅÊõ¤·¤Þ¤¹¡£¤¿¤À¤· Oracle9 °Ê¹ß¤Ç¼ÂÁõ¤µ¤ì¤¿µ¡Ç½¤Ê¤Î¤Ç¤¹¤¬¡¢º£»þ 8i °ÊÁ°¤ò»È¤Ã¤Æ¤ë´Ä¶­¤â¾¯¤Ê¤¤¤È»×¤¦¤Î¤ÇÌäÂê¤Ê¤¤¤Ç¤·¤ç¤¦¡£

MERGE ¹½Ê¸¤ÏÄ̾A¤Î¤è¤¦¤ËÀâÌÀ¤µ¤ì¤Æ¤¤¤ë¤È»×¤¤¤Þ¤¹¡£Oracle ¤Î SQL ¥Þ¥Ë¥å¥¢¥ë¤â°Ê²¼¤Î¤è¤¦¤Ë¤Ê¤Ã¤Æ¤¤¤Þ¤¹¡£

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,¡¡Ž¥Ž¥Ž¥ )

¤Ç¡¢Â¿¤¯¤ÎÎãÂê¤Ë¤ª¤¤¤Æ¤Ï¡¢É½£±¤Èɽ£²¤ò£²¤Ä¤Îɽ¤ò¸µ¤Ë¥´¥Ë¥ç¥´¥Ë¥ç¤Ã¤Æ½èÍý¤¬¤«¤«¤ì¤Æ¤¤¤Æ¡¢¼ÂºÝ¤è¤¯»È¤¦ UPSERT ½èÍý¤È¤ÏÊÌÍÑÅÓ¤ÎÎãÂê¤Ê¤ó¤Ç¤¹¤è¤Í¡£
¤Ã¤Æ¤ï¤±¤Ç¡¢º£¤«¤éÅÐÏ¿¤¹¤ë¥Ç¡¼¥¿¤¬´û¤Ëɽ£±¤Ë¤¢¤ì¤Ð UPDATE ½èÍý¤Ç̵¤±¤ì¤Ð INSERT ½èÍý¤Ã¤Æ¸À¤¦¼ÂºÝ¤Î UPSERT ÍÑÅӤ˧¤·¤¿ÎãÂê¤ò¶¦Í­¤·¤Æ¤ª¤³¤¦¤È»×¤¤¤Þ¤·¤Æ¤³¤Îµ­»ö¤ò½ñ¤¤¤Æ¤¤¤Þ¤¹¡£
¤â¤Ã¤È¤â¡¢ MERGE ¹½Ê¸¤Ç UPSERT ½èÍý¤ò½ñ¤³¤¦¤È»×¤Ã¤¿¤é¡¢¥¢¥ì¡©¤É¤¦¤¹¤ë¤ó¤À¤Ã¤±¡©¤È¾®°ì»þ´Ö¤Û¤ÉǺ¤ó¤À¤Î¤Ç¤³¤¦¤·¤Æ¥á¥â¤Ë»Ä¤·¤Æ¤¤¤ë¤ï¤±¤Ç¤¹¤±¤É¡£(^^¡¶

- ¥¹¥Ý¥ó¥µ¡¼¥ê¥ó¥¯ -

¤µ¤Æ¡¢¼ÂºÝ¤Î UPSERT ÍÑÅÓ¤ËÂбþ¤µ¤»¤ë¤¿¤á¤Ë¤Ï DUAL ɽ¤ò³èÍѤ¹¤ë¼ê¤¬¤¢¤ê¤Þ¤¹¡£¼ÂºÝ¤ËÎã¤ò¸«¤ÆÌ㤦¤Î¤¬Áᤤ¤Ç¤·¤ç¤¦¡£
¤Þ¤º¤Ï¥Æ¥¹¥ÈÍѤÎɽ¤È¥Ç¡¼¥¿¤òºîÀ®¤¹¤ë¡£

CREATE TABLE TEST01 (
  ID             INTEGER PRIMARY KEY,
  TEXT           VARCHAR(30),
  ON_CREATED     DATE DEFAULT SYSDATE
);

INSERT INTO TEST01 (ID, TEXT) VALUES( 1, 'AAAA' );
INSERT INTO TEST01 (ID, TEXT) VALUES( 2, 'BBBB' );
INSERT INTO TEST01 (ID, TEXT) VALUES( 3, 'CCCC' );
commit;
SQL> SELECT * FROM TEST01;

        ID TEXT                           ON_CREAT
---------- ------------------------------ --------
         1 AAAA                           08-07-03
         2 BBBB                           08-07-03
         3 CCCC                           08-07-03

´Ö°ã¤¤¤òÀè¤Ë¼¨¤·¤Æ¤âʶ¤é¤ï¤·¤¤¤Î¤Ç¡¢¤Þ¤º¤ÏÀµ²ò¤«¤é¡£

ID=4, TEXT='DDDD' ¤ò INSERT ½èÍý¤·¤¿¤¤»þ¤Ï¤É¤¦¤¹¤ë¤«¡©

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=4 ¤ÎÎó¤¬ INSERT ¤µ¤ì¤Æ¤¤¤ë¤³¤È¤¬¤ï¤«¤ê¤Þ¤¹¡£

1¹Ô¤¬¥Þ¡¼¥¸¤µ¤ì¤Þ¤·¤¿¡£

SQL> SELECT * FROM TEST01;

        ID TEXT                           ON_CREAT
---------- ------------------------------ --------
         1 AAAA                           08-07-03
         2 BBBB                           08-07-03
         3 CCCC                           08-07-03
         4 DDDD                           08-07-03

¤Ç¤Ï¼¡¤Ë¡¢ID=3, TEXT='DDDD' ¤È UPDATE ½èÍý¤·¤¿¤¤»þ¤Ï¤É¤¦¤¹¤ë¤«¡©

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=3 ¤ÎÎó¤¬ INSERT ¤µ¤ì¤Æ¤¤¤ë¤³¤È¤¬¤ï¤«¤ê¤Þ¤¹¡£

1¹Ô¤¬¥Þ¡¼¥¸¤µ¤ì¤Þ¤·¤¿¡£

SQL> SELECT * FROM TEST01;

        ID TEXT                           ON_CREAT
---------- ------------------------------ --------
         1 AAAA                           08-07-03
         2 BBBB                           08-07-03
         3 DDDD                           08-07-03

¤µ¤Æ¡¢¤³¤ì¤Ç DUAL ɽ¤ò»È¤¦¤È¥¦¥Þ¥¤¶ñ¹ç¤Ë¼«Ê¬¼«¿È¤Îɽ¤ò UPDATE/INSERT ¤Ç¤­¤ë¤³¤È¤¬¤ï¤«¤Ã¤Æ¤­¤¿¤«¤È»×¤¤¤Þ¤¹¡£
´ðËܹ½Ê¸¤Ï¤³¤¦¤Ç¤¹¡£

MERGE¡¡INTO¡¡É½Ì¾1
¡¡¡¡USING¡¡DUAL
¡¡¡¡ON¡¡(Îó̾1 = ÃÍ1,¡¡Îó̾2 = ÃÍ2,¡¡Ž¥Ž¥Ž¥)
WHEN¡¡MATCHED¡¡THEN
¡¡¡¡UPDATE¡¡SET¡¡Îó̾1 = ÃÍ1,¡¡Îó̾2 = ÃÍ2,¡¡Ž¥Ž¥Ž¥
WHEN¡¡NOT¡¡MATCHED¡¡THEN
¡¡¡¡INSERT¡¡[( Îó̾1,¡¡Îó̾2,¡¡Ž¥Ž¥Ž¥ )]¡¡VALUES¡¡( ÃÍ1,¡¡ÃÍ2,¡¡Ž¥Ž¥Ž¥ )

¤µ¤Æ¡¢¼ÂºÝ¤Î¶È̳¤Ë¤ª¤¤¤Æ¤ÏÅöÁ³¤Î¤³¤È¤Î¤è¤¦¤Ë¥Ð¥¤¥ó¥ÉÊÑ¿ô¤ò»È¤¦¤³¤È¤Ë¤Ê¤ë¤Ç¤·¤ç¤¦¡£¼¡¤Ï¥Ð¥¤¥ó¥ÉÊÑ¿ôÂбþ¤Ë¤·¤Æ¤ß¤¿¤¤¤È»×¤¤¤Þ¤¹¡£

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
;
/

¼Â¹Ô·ë²Ì¤Ï¤³¤¦¤Ê¤ê¤Þ¤¹¡£Àµ¾ï¤Ë ID=4 ¤ÎÎó¤¬ INSERT ¤µ¤ì¤Æ¤¤¤ë¤³¤È¤¬¤ï¤«¤ê¤Þ¤¹¡£

PL/SQL¥×¥í¥·¡¼¥¸¥ã¤¬Àµ¾ï¤Ë´°Î»¤·¤Þ¤·¤¿¡£

SQL> SELECT * FROM TEST01;

        ID TEXT                           ON_CREAT
---------- ------------------------------ --------
         1 AAAA                           08-07-03
         2 BBBB                           08-07-03
         3 CCCC                           08-07-03
         4 DDDD                           08-07-03

Ʊ¤¸¤¯¡¢ID=3, TEXT='DDDD' ¤È UPDATE ½èÍý¤·¤¿¤¤»þ¤ò¥Ð¥¤¥ó¥ÉÊÑ¿ô¤Ç¤ä¤Ã¤Æ¤ß¤Þ¤¹¡£id := 3 ¤ÎÉôʬ¤¬°ã¤¦¤À¤±¤Ç¤¹¡£

DECLARE
  id     NUMBER;
  text   VARCHAR(30);
  u_cur  INTEGER;
  u_sql  VARCHAR2(1000);
  u_row  INTEGER;

BEGIN
  id   := 3;
  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
;
/

¼Â¹Ô·ë²Ì¤Ï¤³¤¦¤Ê¤ê¤Þ¤¹¡£Àµ¾ï¤Ë ID=3 ¤ÎÎó¤¬ UPDATE ¤µ¤ì¤Æ¤¤¤ë¤³¤È¤¬¤ï¤«¤ê¤Þ¤¹¡£

PL/SQL¥×¥í¥·¡¼¥¸¥ã¤¬Àµ¾ï¤Ë´°Î»¤·¤Þ¤·¤¿¡£

SQL> SELECT * FROM TEST01;

        ID TEXT                           ON_CREAT
---------- ------------------------------ --------
         1 AAAA                           08-07-03
         2 BBBB                           08-07-03
         3 DDDD                           08-07-03

¤Ä¤Þ¤ê¡¢¥Ð¥¤¥ó¥ÉÊÑ¿ô¤ò»È¤Ã¤¿ MERGE ¹½Ê¸¤Ï¤³¤¦¤Ê¤ê¤Þ¤¹¡£
Ãí°ÕÅÀ¤Ï¡¢UPDATE ¶ç¤ÎÎó̾¤Ë¤Ï ON ¶ç¤Ç»ÈÍѤ·¤¿Îó̾¤Ï»ÈÍѤǤ­¤Ê¤¤¤È¤¤¤¦ÅÀ¤Ç¤¹¡£¤³¤ì¤Ï°ÕÌ£¤ò¹Í¤¨¤ì¤Ð¤ï¤«¤ë¤È»×¤¤¤Þ¤¹¤¬¡¢¥Þ¥Ã¥Á¤·¤Æ¤¤¤ë¼«Ê¬¼«¿È¤Î¥­¡¼¤òÊѹ¹¤Ç¤­¤Ê¤¤¤Ã¤Æ¤ï¤±¤Ç¤¹¡£¥­¡¼°Ê³°¤Ï¹¹¿·²Äǽ¤Ã¤Æ¤ï¤±¤Ç¤¹¡£
INSERT ¶ç¤Ï¤½¤Î¤è¤¦¤ÊÀ©¸Â¤Ï¤¢¤ê¤Þ¤»¤ó¡£¤À¤Ã¤Æ¤Þ¤ÀÉ½Ãæ¤Ë¸ºß¤·¤Æ¤¤¤Ê¤¤¤Î¤Ç¤¹¤«¤é¡£

MERGE¡¡INTO¡¡É½Ì¾1
¡¡¡¡USING¡¡DUAL
¡¡¡¡ON¡¡(Îó̾1 = ?,¡¡Îó̾2 = ?,¡¡Ž¥Ž¥Ž¥)
WHEN¡¡MATCHED¡¡THEN
¡¡¡¡UPDATE¡¡SET¡¡Îó̾n1 = ?,¡¡Îó̾n2 = ?,¡¡Ž¥Ž¥Ž¥
WHEN¡¡NOT¡¡MATCHED¡¡THEN
¡¡¡¡INSERT¡¡[( Îó̾1,¡¡Îó̾2,¡¡Ž¥Ž¥Ž¥ )]¡¡VALUES¡¡( ?,¡¡?,¡¡Ž¥Ž¥Ž¥ )


¤µ¤Æ¡¢Perl DBI ¤«¤é MERGE ¹½Ê¸¤òÍøÍѤ¹¤ë¤Ê¤é¤³¤¦¤Ê¤ê¤Þ¤¹¡£

my $sth = $dbh->prepare(qq{
MERGE INTO TEST01 
  USING DUAL 
  ON ( ID=? ) 
WHEN MATCHED THEN 
  UPDATE SET TEXT=?
WHEN NOT MATCHED THEN
  INSERT ( ID, TEXT ) VALUES ( ?, ? )
});

my $id   = 4;
my $text = 'DDDD';
$sth->execute( $id, $text, $id, $text );

$id   = 3;
$text = 'DDDD';
$sth->execute( $id, $text, $id, $text );

Ʊ¤¸°ú¿ô¤òÅϤ¹¤Î¤¬¤Ê¤ó¤À¤«¡¦¡¦¡¦¤Ã¤Æ´¶¤¸¤ë¾ì¹ç¤Ë¤Ï¡¢¤µ¤é¤Ë MERGE ʸ¤ò¤³¤ó¤Ê´¶¤¸¤ËÊѹ¹¤¹¤ë¤ÈÎɤ¤¤«¤â¤·¤ì¤Þ¤»¤ó¡£

my $sth = $dbh->prepare(qq{
MERGE INTO TEST01 A
  USING (SELECT ? ID, ? TEXT FROM DUAL) B 
  ON ( A.ID=B.ID ) 
WHEN MATCHED THEN 
  UPDATE SET TEXT=B.TEXT
WHEN NOT MATCHED THEN
  INSERT ( ID, TEXT ) VALUES ( B.ID, B.TEXT )
});

my $id   = 4;
my $text = 'DDDD';
$sth->execute( $id, $text );

$id   = 3;
$text = 'DDDD';
$sth->execute( $id, $text );


PL/SQL ¤Ç¤â½ñ¤¤¤Æ¤ª¤¯¤È¤³¤ó¤Ê´¶¤¸¤Ç¤¹¡£ºÇ½ªÅª¤Ë¤ÏËÍ¤Ï DBI ¤«¤é½ñ¤¯¤³¤È¤ò¹Í¤¨¤Æ°Ê²¼¤Î·Á¼°¤¬¼ý¤Þ¤ê¤¬¤è¤¯´¶¤¸¤Æ¤¤¤Þ¤¹¡£

DECLARE
  id     NUMBER;
  text   VARCHAR(30);
  u_cur  INTEGER;
  u_sql  VARCHAR2(1000);
  u_row  INTEGER;

BEGIN
  id   := 3;
  text := 'DDDD';

  u_cur := DBMS_SQL.OPEN_CURSOR;
  u_sql := 'MERGE INTO TEST01 A USING (SELECT :b1 ID, :b2 TEXT FROM DUAL) B ON ( A.ID=B.ID ) WHEN MATCHED THEN UPDATE SET TEXT=B.TEXT WHEN NOT MATCHED THEN INSERT ( ID, TEXT ) VALUES ( B.ID, B.TEXT )';
  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
;
/

´Ö°ã¤¤¤òºÇ¸å¤Ë½ñ¤³¤¦¤«¤È»×¤Ã¤¿¤ó¤Ç¤¹¤±¤É¡¢´Ö°ã¤¤¤Ï½ñ¤«¤Ê¤¯¤Æ¤âÎɤ¤¤È´¶¤¸¤Æ¤­¤¿¤Î¤Ç¡¢¤³¤ì¤Ë¤Æ¤ª½ª¤¤¡£

- ¥¹¥Ý¥ó¥µ¡¼¥ê¥ó¥¯ -

´ØÏ¢¤¹¤ëµ­»ö¡õ¥¹¥Ý¥ó¥µ¡¼¥ê¥ó¥¯