简体   繁体   English

Oracle 更新的多列和不同连接条件

[英]Multiple Columns and different Join Conditions for Oracle update

I have 2 tables, 1 is location and the Other one is Look up table.我有 2 个表,1 个是位置,另一个是查找表。 I have to look into the look up table for the location values and if they are present mark them as 'Y' and 'N' along with their corresponding values我必须查看查找表中的位置值,如果它们存在,则将它们标记为“Y”和“N”以及它们对应的值

在此处输入图像描述

I have written individual update Statements as below:我写了如下的个人更新声明:

**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;

Similarly for 3rd flag and value.对于第三个标志和值也是如此。

Is there a way to write single update for all the three conditions?有没有办法为所有三个条件编写单个更新? Reason why I am looking for single update is that I have 10+ million records and I do not want to scan the records three different times.我寻找单个更新的原因是我有 10+ 百万条记录,我不想扫描记录三个不同的时间。 The lookup table has > 32 million records.查找表有 > 3200 万条记录。

Here is a solution which uses Oracle's bulk FORALL... UPDATE capability.这是一个使用 Oracle 的批量 FORALL... UPDATE 功能的解决方案。 This is not quite as performative as a pure SQL solution but it is simpler to code and the efficiency difference probably won't matter much for 10 million rows on a modern enterprise server, especially if this is a one-off exercise.这不像纯粹的 SQL 解决方案那样具有性能,但它更易于编码,并且对于现代企业服务器上的 1000 万行,效率差异可能并不重要,特别是如果这是一次性练习。

Points to note:注意事项:

  1. You don't say whether LOCATION has a primary key.你没有说 LOCATION 是否有主键。 For this answer I have assumed it has an ID column.对于这个答案,我假设它有一个 ID 列。 The solution won't work if there isn't a primary key, but if your table doesn't have a primary key you've likely got bigger problems.如果没有主键,该解决方案将不起作用,但如果您的表没有主键,您可能会遇到更大的问题。
  2. Your question mentions setting the FLAG columns "as 'Y' and 'N'" but the required output only shows 'Y' setting.您的问题提到将 FLAG 列设置为“Y”和“N” ,但所需的 output 仅显示'Y'设置。 I have included processing for 'N' but see the coda underneath.我已经包括了'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;
/

There is a working demo on db<>fiddle here .这里有一个关于 db<>fiddle的工作演示。 The demo output doesn't exactly match the sample output posted in the query, because that doesn't the given input data.演示 output 与查询中发布的示例 output 不完全匹配,因为这不是给定的输入数据。


Setting flags to 'Y' or 'N'?将标志设置为“Y”还是“N”?

The code above uses left outer joins on the lookup table.上面的代码在查找表上使用了左外连接。 If a row is found the NVL2() function will return 'Y' otherwise it returns 'N'.如果找到一行,NVL2() function 将返回“Y”,否则返回“N”。 This means the flag columns are always populated, regardless of whether the value columns are.这意味着始终填充标志列,无论值列是否存在。 The exception is for rows which have no matches in LOCATION_LOOKUP for any location ( ID=4000 in my demo).例外情况是在任何位置的 LOCATION_LOOKUP 中没有匹配的行(我的演示中的ID=4000 )。 In this case the flag columns will be null.在这种情况下,标志列将是 null。 This inconsistency follows from the inconsistencies in the question.这种不一致源于问题中的不一致。

To resolve it:要解决它:

  • if you want all flag columns to be populated with 'N' remove the WHERE clause from the get_locations cursor query.如果您希望使用'N'填充所有标志列,请从get_locations查询中删除 WHERE 子句。
  • if you don't want to set flags to 'N' change the NVL2() function calls accordingly: nvl2(lup1.value, 'Y', null) as l1flag如果您不想将标志设置为'N' ,请相应更改 NVL2() function 调用: nvl2(lup1.value, 'Y', null) as l1flag

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM