我有一个地址表(包含k_id-PK,地址)和一个add_hist日志表(包含k_id,地址,更改日期),即它具有每个id的所有地址以及更改日期地址。
我想创建一个更新查询,它将更新地址表中的地址列,因此,从add_hist表中获取最新地址将完成这项工作。我几乎完成了我的查询。它也取得了正确的结果。但我想如果地址表已经更新,那么就不要更新它。这是我的查询。请检查并更正它以获得所需的结果。
update address a set k_add =
(select kad from (
select h.k_id kid, h.k_add kad, h.chg_dt from add_hist h,
(select k_id, max(chg_dt) ch from add_hist
group by k_id
) h1
where h1.k_id = h.k_id
and h1.ch=h.chg_dt
) h2
where h2.kid = a.k_id)
;
答案 0 :(得分:1)
您可以使用合并而不是更新:
merge into address a
using (
select k_id, max(k_add) keep (dense_rank last order by chg_dt) as k_add
from add_hist
group by k_id
) h
on (a.k_id = h.k_id)
when matched then
update set a.k_add = h.k_add
where (a.k_add is null and h.k_add is not null)
or (a.k_add is not null and h.k_add is null)
or a.k_add != h.k_add;
using
子句中的查询从历史记录表中查找每个ID的最新地址。当主表上存在匹配的ID时,由于where
子句,但只有在值不同时才会更新。
使用一些虚拟数据:
create table address (k_id number primary key, k_add varchar2(20));
create table add_hist (k_id number, k_add varchar2(20), chg_dt date);
insert into address (k_id, k_add) values (1, 'Address 1');
insert into address (k_id, k_add) values (2, 'Address 2');
insert into address (k_id, k_add) values (3, null);
insert into address (k_id, k_add) values (4, null);
insert into add_hist (k_id, k_add, chg_dt) values (1, 'Address 1', date '2017-01-01');
insert into add_hist (k_id, k_add, chg_dt) values (1, 'Address 2', date '2017-01-02');
insert into add_hist (k_id, k_add, chg_dt) values (1, 'Address 1', date '2017-01-03');
insert into add_hist (k_id, k_add, chg_dt) values (2, 'Address 1', date '2017-01-01');
insert into add_hist (k_id, k_add, chg_dt) values (2, 'Address 2', date '2017-01-02');
insert into add_hist (k_id, k_add, chg_dt) values (2, 'Address 3', date '2017-01-03');
insert into add_hist (k_id, k_add, chg_dt) values (3, 'Address 1', date '2017-01-01');
insert into add_hist (k_id, k_add, chg_dt) values (3, null, date '2017-01-02');
insert into add_hist (k_id, k_add, chg_dt) values (4, 'Address 1', date '2017-01-01');
commit;
运行更新语句:
4 rows updated.
select * from address;
K_ID K_ADD
---------- --------------------
1 Address 1
2 Address 3
3
4 Address 1
回滚到起始状态后,运行合并得到:
2 rows merged.
select * from address;
K_ID K_ADD
---------- --------------------
1 Address 1
2 Address 3
3
4 Address 1
相同的最终结果,但合并了1行,而不是更新了2行。
(如果在没有where
子句的情况下运行合并,则所有四行仍然受到影响;如果没有空检查,则只更新ID为2的行。
答案 1 :(得分:1)
您可以使用UPDATE
语句获得所需的结果。具体来说,您需要通过加入进行更新。"但语法必须精确。 Update with joins
使用与Alex的答案相同的设置,以下update
语句将更新一行。
编辑:请参阅此答案下方的Alex Poole的评论。此处提出的解决方案仅适用于Oracle 12.1及更高版本。问题不在于通过加入&#34;更新。概念,但源行集是聚合的结果。它与Oracle在编译时知道&#34; join&#34;的关系有关。源行集中的列是唯一的(它没有重复项)。在旧版本的Oracle中,需要显式的唯一或主键约束或索引。当然,当我们GROUP BY <col>
时,<col>
在聚合的结果集中将是唯一的,但它不会有唯一的约束或索引。似乎Oracle认识到了这种情况,并且从12.1开始它允许update through join
,其中源表是聚合的结果,如本例所示。
update
( select a.k_add as current_address, q.new_address
from (
select k_id,
min(k_add) keep (dense_rank last order by chg_dt) as new_address
from add_hist
group by k_id
) q
join
address a on a.k_id = q.k_id
)
set current_address = new_address
where current_address != new_address
or current_address is null and new_address is not null
or current_address is not null and new_address is null
;