Хочешь обновить и вставить на одной ручке, оба они не только один - PullRequest
0 голосов
/ 02 марта 2020

У меня есть таблица, в которой хранится информация о странах, и я должен изменить ISO-код с 3 символов на 2 символа ISO. например, у меня есть такие данные.

this is how data is stored

и вопрос , сначала я хочу обновить все из них, которые состоят из 3 цифр, заданных valid_until = '31 .12.2019 'и вставьте новую строку, которая должна выглядеть следующим образом:

this

Да, я знаю, что происходит слияние, но мне нужно обновить и вставить не только одну.

Ответы [ 2 ]

2 голосов
/ 02 марта 2020

Если у вас есть другой источник кодов, это просто вставка / обновление:

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;

Вы можете заключить это в одну транзакцию, если хотите, чтобы они вступили в силу "одновременно ».

0 голосов
/ 02 марта 2020

Согласитесь с Алексом и Гордоном, что это можно запустить как 2 оператора, заключенные в одну транзакцию. Итак, не совсем понятно, почему это должен быть один оператор SQL. Я попытался использовать повторяющиеся строки в предложении using в merge, чтобы обновление и вставка происходили вместе (см. Фрагмент ниже). Пожалуйста, проверьте, хотите ли вы этого достичь.

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  |
...