Oracle 更新的多列和不同的连接条件
Multiple Columns and different Join Conditions for Oracle update
我有 2 个 tables,1 个是位置,另一个是查找 table。我必须查看查找 table 的位置值,如果它们存在,则将它们标记为 'Y' 和 'N' 以及它们相应的值
个人更新语句如下:
**Location1,L1value**
Update Location
set (Location1,L1value) =
(select UPPER(VAlue),'Y' from Location_lookup where trim(Location1)=Location
where exists (select 1 from Location_lookup where trim(Location1)=Location);
commit;
**Location2,value**
Update Location
set (Location2,L2value) =
(select UPPER(VAlue),'Y' from Location_lookup where trim(Location2)=Location
where exists (select 1 from Location_lookup where trim(Location2)=Location);
commit;
与第三个标志和值类似。
有没有办法为所有三个条件编写单个更新?我寻找单一更新的原因是我有 10+ 百万条记录,我不想扫描记录三次。查找 table 有超过 3200 万条记录。
这是一个使用 Oracle 的批量 FORALL ... UPDATE 功能的解决方案。这不如纯 SQL 解决方案那么有效,但它的代码更简单,对于现代企业服务器上的 1000 万行,效率差异可能并不重要,特别是如果这是一次性练习.
注意事项:
- 你不说LOCATION有没有主键。对于这个答案,我假设它有一个 ID 列。如果没有主键,该解决方案将不起作用,但如果您的 table 没有主键,您可能会遇到更大的问题。
- 您的问题提到将 FLAG 列 " 设置为 'Y' 和 'N'",但所需的输出仅显示
'Y'
设置。我已经包含了 'N'
的处理,但看到下面的尾声。
declare
cursor get_locations is
with lkup as (
select *
from location_lookup
)
select locn.id
,locn.location1
,upper(lup1.value) as l1value
,nvl2(lup1.value, 'Y', 'N') as l1flag
,locn.location2
,upper(lup2.value) as l2value
,nvl2(lup2.value, 'Y', 'N') as l2flag
,locn.location3
,upper(lup3.value) as l3value
,nvl2(lup3.value, 'Y', 'N') as l3flag
from location locn
left outer join lkup lup1 on trim(locn.location1) = lup1.location
left outer join lkup lup2 on trim(locn.location2) = lup2.location
left outer join lkup lup3 on trim(locn.location3) = lup3.location
where lup1.location is not null
or lup2.location is not null
or lup3.location is not null;
type t_locations_type is table of get_locations%rowtype index by binary_integer;
t_locations t_locations_type;
begin
open get_locations;
loop
fetch get_locations bulk collect into t_locations limit 10000;
exit when t_locations.count() = 0;
forall idx in t_locations.first() .. t_locations.last()
update location
set l1value = t_locations(idx).l1value
,l1flag = t_locations(idx).l1flag
,l2value = t_locations(idx).l2value
,l2flag = t_locations(idx).l2flag
,l3value = t_locations(idx).l3value
,l3flag = t_locations(idx).l3flag
where id = t_locations(idx).id;
end loop;
close get_locations;
end;
/
有一个工作演示 on db<>fiddle here。演示输出与查询中发布的示例输出不完全匹配,因为它不是给定的输入数据。
正在将标志设置为 'Y' 或 'N'?
上面的代码在查找时使用了左外连接 table。如果找到一行,NVL2() 函数将 return 'Y' 否则它 returns 'N'。这意味着标志列总是被填充,不管值列是否被填充。例外情况是在任何位置的 LOCATION_LOOKUP 中没有匹配项的行(在我的演示中为 ID=4000
)。在这种情况下,标志列将为空。这种不一致源于问题中的不一致。
解决方法:
- 如果你想用
'N'
填充所有标志列,请从 get_locations
游标查询中删除 WHERE 子句。
- 如果您不想将标志设置为
'N'
,请相应地更改 NVL2() 函数调用:nvl2(lup1.value, 'Y', null) as l1flag
我有 2 个 tables,1 个是位置,另一个是查找 table。我必须查看查找 table 的位置值,如果它们存在,则将它们标记为 'Y' 和 'N' 以及它们相应的值
个人更新语句如下:
**Location1,L1value**
Update Location
set (Location1,L1value) =
(select UPPER(VAlue),'Y' from Location_lookup where trim(Location1)=Location
where exists (select 1 from Location_lookup where trim(Location1)=Location);
commit;
**Location2,value**
Update Location
set (Location2,L2value) =
(select UPPER(VAlue),'Y' from Location_lookup where trim(Location2)=Location
where exists (select 1 from Location_lookup where trim(Location2)=Location);
commit;
与第三个标志和值类似。
有没有办法为所有三个条件编写单个更新?我寻找单一更新的原因是我有 10+ 百万条记录,我不想扫描记录三次。查找 table 有超过 3200 万条记录。
这是一个使用 Oracle 的批量 FORALL ... UPDATE 功能的解决方案。这不如纯 SQL 解决方案那么有效,但它的代码更简单,对于现代企业服务器上的 1000 万行,效率差异可能并不重要,特别是如果这是一次性练习.
注意事项:
- 你不说LOCATION有没有主键。对于这个答案,我假设它有一个 ID 列。如果没有主键,该解决方案将不起作用,但如果您的 table 没有主键,您可能会遇到更大的问题。
- 您的问题提到将 FLAG 列 " 设置为 'Y' 和 'N'",但所需的输出仅显示
'Y'
设置。我已经包含了'N'
的处理,但看到下面的尾声。
declare
cursor get_locations is
with lkup as (
select *
from location_lookup
)
select locn.id
,locn.location1
,upper(lup1.value) as l1value
,nvl2(lup1.value, 'Y', 'N') as l1flag
,locn.location2
,upper(lup2.value) as l2value
,nvl2(lup2.value, 'Y', 'N') as l2flag
,locn.location3
,upper(lup3.value) as l3value
,nvl2(lup3.value, 'Y', 'N') as l3flag
from location locn
left outer join lkup lup1 on trim(locn.location1) = lup1.location
left outer join lkup lup2 on trim(locn.location2) = lup2.location
left outer join lkup lup3 on trim(locn.location3) = lup3.location
where lup1.location is not null
or lup2.location is not null
or lup3.location is not null;
type t_locations_type is table of get_locations%rowtype index by binary_integer;
t_locations t_locations_type;
begin
open get_locations;
loop
fetch get_locations bulk collect into t_locations limit 10000;
exit when t_locations.count() = 0;
forall idx in t_locations.first() .. t_locations.last()
update location
set l1value = t_locations(idx).l1value
,l1flag = t_locations(idx).l1flag
,l2value = t_locations(idx).l2value
,l2flag = t_locations(idx).l2flag
,l3value = t_locations(idx).l3value
,l3flag = t_locations(idx).l3flag
where id = t_locations(idx).id;
end loop;
close get_locations;
end;
/
有一个工作演示 on db<>fiddle here。演示输出与查询中发布的示例输出不完全匹配,因为它不是给定的输入数据。
正在将标志设置为 'Y' 或 'N'?
上面的代码在查找时使用了左外连接 table。如果找到一行,NVL2() 函数将 return 'Y' 否则它 returns 'N'。这意味着标志列总是被填充,不管值列是否被填充。例外情况是在任何位置的 LOCATION_LOOKUP 中没有匹配项的行(在我的演示中为 ID=4000
)。在这种情况下,标志列将为空。这种不一致源于问题中的不一致。
解决方法:
- 如果你想用
'N'
填充所有标志列,请从get_locations
游标查询中删除 WHERE 子句。 - 如果您不想将标志设置为
'N'
,请相应地更改 NVL2() 函数调用:nvl2(lup1.value, 'Y', null) as l1flag