oracle合并两表时合并条件的问题
Problem in merge condition in oracle when merging two tables
我有一个 table,其中的数据为:
id payor_name
---------------
1 AETNA
2 UMR
3 CIGNA
4 METLIFE
4 AETNAU
5 ktm
6 ktm
Id
和payor_name
是两个columns.So,
我的预期输出是:
id payor_name
---------------
1 AETNA
2 UMR
3 CIGNA
4 METLIFE
4 AETNAU
6 ktm ...> I want to change the id of this row to be 6 from 5.
6 ktm
我想要id和payor_name.So之间的一对一映射,这是我试过的:
MERGE INTO offc.payor_collec A
USING (select id from offc.payor_collec where payor_name in(
select payor_name from offc.payor_collec group by payor_name having count(distinct id)>=2)) B
ON (A.id=B.id)
WHEN MATCHED THEN
UPDATE SET A.id=B.id
但是当我编译时出现错误:
Error at line 1
ORA-38104: Columns referenced in the ON Clause cannot be updated: "A"."ID"
Id 是数字,其中 payor_name 是 varchar2。
我怎样才能达到这个结果?
使用相关子查询:
UPDATE PAYOR_COLLEC pc
SET pc.ID = (SELECT MAX(pc2.ID)
FROM PAYOR_COLLEC pc2
WHERE pc2.PAYOR_NAME = pc.PAYOR_NAME)
MERGE
有效,但与您的代码略有不同。
SQL> select * from test;
ID PAYOR
---------- -----
1 aetna
2 umr
5 ktm
6 ktm
SQL> merge into test t
2 using (select max(t1.id) id,
3 t1.payor_name
4 from test t1
5 group by t1.payor_name
6 ) x
7 on (x.payor_name = t.payor_name)
8 when matched then update set
9 t.id = x.id;
4 rows merged.
SQL> select * from test;
ID PAYOR
---------- -----
1 aetna
2 umr
6 ktm
6 ktm
SQL>
您可以使用 MERGE
语句,正如您尝试过的和 Littlefoot 所展示的那样。
您也可以使用 Bob Jarvis 展示的相关子查询,但那样效率很低。
许多 Oracle 开发人员并不知道您还可以通过联接进行更新。更糟糕的是,还有很多人说 "there is no such thing in Oracle."
在你的问题中,你需要将你的 table 连接到聚合查询(只为每个 payor_name 选择最大 ID)并且连接在 group by
列中聚合体。这已经保证了右侧的连接列是唯一的 table;这就是 Oracle 允许通过连接进行更新所需的全部内容。
这是一个完整的示例,从 create table
语句开始,然后是 update
,然后显示更新后的 table。请注意,我不需要任何约束(如主键、非空、唯一等)或基于 table 的索引。如果它们确实存在,那就更好了,但该解决方案适用于大多数一般情况。
create table t (id, payor_name) as
select 1, 'AETNA' from dual union all
select 2, 'UMR' from dual union all
select 3, 'CIGNA' from dual union all
select 4, 'METLIFE' from dual union all
select 4, 'AETNAU' from dual union all
select 5, 'ktm' from dual union all
select 6, 'ktm' from dual;
Table T created.
update
(
select id, payor_name, max_id
from t inner join
(select max(id) as max_id, payor_name from t group by payor_name)
using (payor_name)
)
set id = max_id where id != max_id
;
1 row updated.
select * from t;
ID PAYOR_NAME
----- ----------
1 AETNA
2 UMR
3 CIGNA
4 METLIFE
4 AETNAU
6 ktm
6 ktm
还要注意 update
语句末尾的 where
子句。您不想将行更新为它们预先存在的值;这仍然会生成撤消和重做数据(尽管我知道 Oracle 在最近的版本中已经改变了它 - 它现在不会生成撤消和重做,除非一行确实发生了变化)。我假设 ID 不是 NULL - 否则你应该将 where
子句重写为
where decode(id, max_id, 0) is null
或同等学历
我有一个 table,其中的数据为:
id payor_name
---------------
1 AETNA
2 UMR
3 CIGNA
4 METLIFE
4 AETNAU
5 ktm
6 ktm
Id
和payor_name
是两个columns.So,
我的预期输出是:
id payor_name
---------------
1 AETNA
2 UMR
3 CIGNA
4 METLIFE
4 AETNAU
6 ktm ...> I want to change the id of this row to be 6 from 5.
6 ktm
我想要id和payor_name.So之间的一对一映射,这是我试过的:
MERGE INTO offc.payor_collec A
USING (select id from offc.payor_collec where payor_name in(
select payor_name from offc.payor_collec group by payor_name having count(distinct id)>=2)) B
ON (A.id=B.id)
WHEN MATCHED THEN
UPDATE SET A.id=B.id
但是当我编译时出现错误:
Error at line 1
ORA-38104: Columns referenced in the ON Clause cannot be updated: "A"."ID"
Id 是数字,其中 payor_name 是 varchar2。
我怎样才能达到这个结果?
使用相关子查询:
UPDATE PAYOR_COLLEC pc
SET pc.ID = (SELECT MAX(pc2.ID)
FROM PAYOR_COLLEC pc2
WHERE pc2.PAYOR_NAME = pc.PAYOR_NAME)
MERGE
有效,但与您的代码略有不同。
SQL> select * from test;
ID PAYOR
---------- -----
1 aetna
2 umr
5 ktm
6 ktm
SQL> merge into test t
2 using (select max(t1.id) id,
3 t1.payor_name
4 from test t1
5 group by t1.payor_name
6 ) x
7 on (x.payor_name = t.payor_name)
8 when matched then update set
9 t.id = x.id;
4 rows merged.
SQL> select * from test;
ID PAYOR
---------- -----
1 aetna
2 umr
6 ktm
6 ktm
SQL>
您可以使用 MERGE
语句,正如您尝试过的和 Littlefoot 所展示的那样。
您也可以使用 Bob Jarvis 展示的相关子查询,但那样效率很低。
许多 Oracle 开发人员并不知道您还可以通过联接进行更新。更糟糕的是,还有很多人说 "there is no such thing in Oracle."
在你的问题中,你需要将你的 table 连接到聚合查询(只为每个 payor_name 选择最大 ID)并且连接在 group by
列中聚合体。这已经保证了右侧的连接列是唯一的 table;这就是 Oracle 允许通过连接进行更新所需的全部内容。
这是一个完整的示例,从 create table
语句开始,然后是 update
,然后显示更新后的 table。请注意,我不需要任何约束(如主键、非空、唯一等)或基于 table 的索引。如果它们确实存在,那就更好了,但该解决方案适用于大多数一般情况。
create table t (id, payor_name) as
select 1, 'AETNA' from dual union all
select 2, 'UMR' from dual union all
select 3, 'CIGNA' from dual union all
select 4, 'METLIFE' from dual union all
select 4, 'AETNAU' from dual union all
select 5, 'ktm' from dual union all
select 6, 'ktm' from dual;
Table T created.
update
(
select id, payor_name, max_id
from t inner join
(select max(id) as max_id, payor_name from t group by payor_name)
using (payor_name)
)
set id = max_id where id != max_id
;
1 row updated.
select * from t;
ID PAYOR_NAME
----- ----------
1 AETNA
2 UMR
3 CIGNA
4 METLIFE
4 AETNAU
6 ktm
6 ktm
还要注意 update
语句末尾的 where
子句。您不想将行更新为它们预先存在的值;这仍然会生成撤消和重做数据(尽管我知道 Oracle 在最近的版本中已经改变了它 - 它现在不会生成撤消和重做,除非一行确实发生了变化)。我假设 ID 不是 NULL - 否则你应该将 where
子句重写为
where decode(id, max_id, 0) is null
或同等学历