更新另一列时,使用列名作为 PL/SQL 关联数组的键

Posted

技术标签:

【中文标题】更新另一列时,使用列名作为 PL/SQL 关联数组的键【英文标题】:Use column name as key for PL/SQL associative array when updating another column 【发布时间】:2018-12-21 11:13:28 【问题描述】:

我有一个包含两列数据的 Excel 表格。 A 列是代码,B 列是相应的国家名称。我把它变成了一个关联数组,ueln_country

现在的任务是更新HORSE 表的列COUNTRY_OF_RESIDENCE。 Horses 有一列 UELN,其中前三个字母对应 Excel 表中的代码。

我必须检查代码是否存在于 Excel 表中。如果是这样,我必须用CLASSIFICATOR.code 更新HORSE.country_of_residence,其中CLASSIFICATOR.name = **the corresponding country in column B** andCLASSIFICATOR.dom_code = 'ISOCODE'`。

第一次尝试得到错误

PLS-00201:必须声明标识符“UELN”

据我了解,这是因为我只能在 PL/SQL 语句中使用声明的变量。

declare
  type TBL_UELN_COUNTRY is table of varchar2(50) index by varchar2 (3);
  test                  TBL_UELN_COUNTRY;
  ueln_country          TBL_UELN_COUNTRY;

begin
  ueln_country('008') := 'ALBAANIA';
  ueln_country('010') := 'ANTARKTIS';
  ueln_country('011') := 'ANTARKTIS';
  ....

  update HORSE
  set COUNTRY_OF_RESIDENCE=
      when (...dummy_case...) then
        (select code from meta.classifcator 
         where dom_code = 'ISOCODE' 
         and name = ueln_country(substr(UELN, 1, 3)))
  where UELN is not null;
end;
/

第二次尝试。

因此,由于第一个错误,我试图以某种方式声明变量。

我知道这行不通(ORA-01422:精确提取返回的行数超过了请求的行数),但它显示了我的想法的发展方向:

declare
  type TBL_UELN_COUNTRY is table of varchar2(50) index by varchar2 (3);
  test                  TBL_UELN_COUNTRY;
  ueln_country          TBL_UELN_COUNTRY;

  v_ueln horse.UELN%TYPE;

begin

  select UELN into v_ueln from HORSE;

  ueln_country('008') := 'ALBAANIA';
  ueln_country('010') := 'ANTARKTIS';
  ueln_country('011') := 'ANTARKTIS';
  ....


  update HORSE
  set COUNTRY_OF_RESIDENCE=
      when (...dummy_case...) then
        (select code from meta.classifcator 
         where dom_code = 'ISOCODE'
         and name = ueln_country(substr(v_ueln, 1, 3)))
  where UELN is not null;
end;
/

所以我想从键 = substr(specific_horse.UELN, 1, 3) 的关联数组中选择一个值。

在 Google 和 Stack 中搜索了几个小时,但没有找到答案。


丑陋且工作速度非常慢的解决方案就是我没有创建关联数组,而是以when -key- then select code from meta.classificator where dom_code = 'ISOKOOD' and name = -value- 之类的形式为每个 Excel 表格行创建了 400 多个案例

【问题讨论】:

在您的子查询中使用联接我已经修改了第一个示例,如果可行,我将发布完整的答案。 update HORSE set COUNTRY_OF_RESIDENCE= when (...dummy_case...) then (select code from meta.classifcator M JOIN HORSE H ON H.UELN = M.NAME where dom_code = 'ISOCODE' and M.name = ueln_country(substr( H.UELN, 1, 3))) 其中 UELN 不为空; Edit 您的问题并为两个表添加示例 ddl 以模拟问题。我不明白使用关联数组的原因。您不能将行加载到临时表中或将文件导入为 csv,然后使用相关表中的连接(合并/相关更新)进行更新吗? 【参考方案1】:

关联数组不能在 SQL 中使用。 如果你在SQL中使用像array(index)这样的表达式,那么实际上PL/SQL引擎通过索引获取值,然后在执行SQL语句之前将结果绑定到SQL引擎

更具体

declare
  type TBL_UELN_COUNTRY is table of varchar2(50) index by varchar2 (3);
  test                  TBL_UELN_COUNTRY;
  dummy varchar2(30);
begin
  test('GBP') := 'UK';
  test('USD') := 'USA';

  select /*+ qwerty */ test('GBP')
  into dummy
  from dual;  
end;
/

如果我们检查游标的绑定,我们会看到实际绑定值的类型为 VARCHAR(128) - :B1。 PL/SQL 代码中的test('GBP') 作为绑定变量 B1 传递。

SQL> column sql_text format a50
SQL> select sbc.datatype_string, sql_text
  2    from v$sql s join v$sql_bind_capture sbc
  3      on s.sql_id = sbc.sql_id
  4   where lower(sql_text) not like '%v$sql%'
  5     and lower(sql_fulltext) like 'select %qwerty%';

DATATYPE_STRING SQL_TEXT
--------------- --------------------------------------------------
VARCHAR2(128)   SELECT /*+ qwerty */ :B1 FROM DUAL

SQL 引擎对关联数组一无所知,显然它无法将值传递和索引到数组并取回数组的元素。

如果您仍想使用关联数组来查找某些值,您可以声明包变量和getter 函数(您可能还希望实现逻辑来处理数组中没有元素的情况给定索引 - 否则在这种情况下你会得到运行时异常)。

create or replace package pkg as

  function GetCountry(idx in varchar2) return varchar2;

end pkg;
/
sho err

create or replace package body pkg as

  type TBL_UELN_COUNTRY is table of varchar2(50) index by varchar2 (3);

  test pkg.TBL_UELN_COUNTRY;

  function GetCountry(idx in varchar2) return varchar2 as
    begin return test(idx); end;

-- initializing
begin
  test('GBP') := 'UK';
  test('USD') := 'USA';
end pkg;
/
sho err

最后

SQL> set serveroutput on
SQL> declare
  2    dummy varchar2(30);
  3  begin
  4    with t(idx) as (select 'GBP' from dual)
  5    select pkg.GetCountry(t.idx)
  6    into dummy
  7    from t;
  8    dbms_output.put_line(dummy);
  9  end;
 10  /
UK

PL/SQL procedure successfully completed.

【讨论】:

以上是关于更新另一列时,使用列名作为 PL/SQL 关联数组的键的主要内容,如果未能解决你的问题,请参考以下文章

更新另一列时自动更新sql列

Oracle PL/SQL - 循环值作为没有动态 SQL 的动态列名

触发器 - 如何在更新另一列时更改另一列 - MySQL

pl/sql-create trigger on a table - 每当在同一个表中插入新记录时,应更新表的另一列

当您需要基于另一列更新列时,在 Pandas 中循环的替代方法

PL/SQL 游标使用参数作为列名