想同时更新和插入,两者都不是一个

Want to update and insert at the same tame, both of them not only one

我有一个 table,其中存储了有关国家/地区的信息,我必须将 ISO 代码从 3 个字符更改为 2 个字符的 ISO 代码。 例如我有这样的数据。

问题是,首先我想更新所有由 3 个数字组成的 valid_until = '31.12.2019' 并插入新行应该看起来像

是的,我知道有合并,但我需要更新和插入,而不是只有一个。

假设您有其他代码来源,这只是一个 insert/update:

update t
    set valid_until = date '2019-12-31'
    where length(iso_code) = 3;

insert into t (iso_code, valid_from, valid_to)
    select cs.iso_code_3, date '1940-01-01', date '3199-12-31'
    from t join
         codesource cs
         on t.iso_code = cs.iso_code_2;

如果您希望它们生效,您可以将其包装到单个事务中"at the same time"。

同意 Alex 和 Gordon 的观点,这可以 运行 作为包含在单个事务中的 2 个语句。所以,不太清楚为什么这需要一个 SQL 语句。我尝试在 merge 中的 using 子句中使用重复行来使更新和插入同时发生(请参见下面的代码片段)。请检查这是否是您想要实现的目标。

SQLFiddle这里

    SQL> create table foo
      2  as
      3     select 'AD' iso_code,
      4            date '2020-01-01' valid_from,
      5            date '3999-12-31' valid_until
      6       from dual;


    SQL> select * from foo;
         |  ISO_CODE    |   VALID_FROM  |   VALID_UNTIL |
         |  AD          |   1/1/2020    |   12/31/3999  |


    SQL> alter table foo modify iso_code varchar2(3);

    SQL> create table iso_code_mapping
      2  as
      3     select 'AD' iso2_code, 'AND' iso3_code from dual;


    SQL> select * from iso_code_mapping;
         |  ISO2_CODE   |   ISO3_CODE   |
         |  AD          |   AND         |


    SQL> merge into foo
      2  using (
      3       select iso_code, iso3_code, valid_from, valid_until from foo f
      4                  join iso_code_mapping i on i.iso2_code = f.iso_code
      5              union all
      6              select iso_code||'_2' iso_code, iso3_code, valid_from, valid_until from foo f
      7                  join iso_code_mapping i on i.iso2_code = f.iso_code
      8                  where not exists ( select 1 from foo f2 where f2.iso_code = i.iso3_code and f2.valid_until = '31 DEC 3999' )
      9         ) x
     10  on ( x.iso_code = foo.iso_code )
     11  when matched then
     12      update set valid_until = '31 DEC 2019'
     13      where valid_until <> '31 DEC 2019'
     14  when not matched then
     15      insert (iso_code, valid_from, valid_until)
     16      values (iso3_code, '1 JAN 1940', '31 DEC 3999')
     17  ;


    SQL> select * from foo;
         |  ISO_CODE    |   VALID_FROM  |   VALID_UNTIL |
         |  AD          |   1/1/2020    |   12/31/2019  |
         |  AND         |   1/1/1940    |   12/31/3999  |