sql—oracle更新的多列和不同的联接条件

r8xiu3jd  于 2021-07-29  发布在  Java
关注(0)|答案(1)|浏览(363)

我有两个表,一个是位置表,另一个是查找表。我必须查看查找表中的位置值,如果它们存在,则将它们与相应的值一起标记为“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;

第三个标志和值也是如此。
有没有一种方法可以为这三个条件编写一个更新?为什么我要寻找单一的更新是因为我有1000多万条记录,我不想扫描记录三次不同的时间。查找表有超过3200万条记录。

dxxyhpgq

dxxyhpgq1#

这里有一个解决方案,它使用oracle的大容量。。。更新功能。这并不像纯sql解决方案那样具有很高的性能,但是它更易于编码,而且对于现代企业服务器上的1000万行来说,效率差异可能不会有多大影响,特别是如果这是一个一次性的练习的话。
注意事项:
你不能说位置是否有主键。对于这个答案,我假设它有一个id列。如果没有主键,解决方案将不起作用,但是如果表没有主键,则可能会遇到更大的问题。
您的问题提到将标志列设置为“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;
/

这里有一个关于db<>fiddle的工作演示。演示输出与查询中发布的示例输出不完全匹配,因为这与给定的输入数据不匹配。
将标志设置为“y”或“n”?
上面的代码在查找表上使用左外部联接。如果找到一行,nvl2()函数将返回“y”,否则返回“n”。这意味着无论值列是否为空,标志列总是被填充的。例外情况是在位置查找中没有与任何位置匹配的行( ID=4000 在我的演示中)。在这种情况下,标志列将为空。这种不一致性源于问题中的不一致性。
解决方法:
如果希望所有标志列都填充 'N' 从中删除where子句 get_locations 游标查询。
如果不想将标志设置为 'N' 相应地更改nvl2()函数调用: nvl2(lup1.value, 'Y', null) as l1flag

相关问题