更新另一列时,使用列名作为 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** and
CLASSIFICATOR.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 关联数组的键的主要内容,如果未能解决你的问题,请参考以下文章
Oracle PL/SQL - 循环值作为没有动态 SQL 的动态列名
pl/sql-create trigger on a table - 每当在同一个表中插入新记录时,应更新表的另一列