Update table with result of query without deleting and inserting the same row?

时间:2015-12-03 10:37:26

标签: oracle plsql oracle12c

I have a table foo:

CREATE TABLE foo (
  bar   NUMBER NOT NULL,
  value VARCHAR2(10) NOT NULL
)

Now, in a PL/SQL procedure, I want to change the list of values for a specific value for bar so that it contains exactly those returned from a rather complicated select query:

SELECT * FROM (
  SELECT
    x bar,
    regexp_substr(y,'[^ ]+', 1, level) value
  FROM dual
  CONNECT BY regexp_substr(y, '[^ ]+', 1, level) IS NOT NULL
) WHERE TRIM(value) IS NOT NULL;

This means I have to (1) delete all rows not returned by that query, and (2) insert all rows from that query that are not already in foo. So for instance if foo contains this,

1   A
2   A
2   B
2   C

the variable x is 2 and the query above returns this (as y is C D)

2   C
2   D

I would like to end up with a table foo like this:

1   A
2   C
2   D

Currently I do this by first deleting all rows where bar = x and then inserting all the rows from the query:

DELETE FROM foo WHERE bar = x;
INSERT INTO foo
SELECT * FROM /* the full query edited out for compactness */;

The problem is that this messes up my revision control system since I often delete rows and then directly afterwards insert the exact same row again. Is there any way to do this without deleting the rows that will be inserted again? I would prefer to only type the query once, since it is rather long.

1 个答案:

答案 0 :(得分:1)

插入/删除foo和foo的新值之间的区别怎么样?

delete foo ff
 where exists(with c_query as ( 
               -- result of your complex query
               select 2 as bar, 'C' as value
                 from dual
               union all
               select 2 as bar, 'D' as value from dual)
              -- delete foo not in c_query
              (select f.bar, f.value
                 from foo f
                where f.bar = (select distinct bar from c_query)
                  and ff.bar = f.bar
                  and ff.value = f.value
               minus
               select d.bar, d.value from c_query d));

insert into foo
  with c_query as
   ( -- result of your complex query
    select 2 as bar, 'C' as value
      from dual
    union all
    select 2 as bar, 'D' as value from dual)
  -- insert c_query data not in foo    
   (select d.bar, d.value
      from c_query d
    minus
    select f.bar, f.value from foo f);