想同时更新和插入,两者都不是一个
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
子句中使用重复行来使更新和插入同时发生(请参见下面的代码片段)。请检查这是否是您想要实现的目标。
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 |
我有一个 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
子句中使用重复行来使更新和插入同时发生(请参见下面的代码片段)。请检查这是否是您想要实现的目标。
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 |