Использовать имя столбца в качестве ключа для ассоциативного массива PL / SQL при обновлении другого столбца - PullRequest
0 голосов
/ 21 декабря 2018

У меня есть таблица Excel с двумя столбцами данных.Столбец A - это коды, столбец B - соответствующие названия стран.Я превратил его в ассоциативный массив, ueln_country.

Теперь задача состоит в том, чтобы обновить HORSE столбец таблицы COUNTRY_OF_RESIDENCE.У лошадей есть столбец UELN, где первые три буквы соответствуют кодам в таблице Excel.

Я должен проверить, существует ли код в таблице Excel.Если это произойдет, я должен обновить HORSE.country_of_residence с CLASSIFICATOR.code, где 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 в течение нескольких часов и нене могу найти ответ.


Уродливое и очень медленное рабочее решение было именно тем, где я не создал ассоциативный массив и сделал 400+ случаев для каждой строки таблицы Excel в форме, подобной when -key- then select code from meta.classificator where dom_code = 'ISOKOOD' and name = -value-

1 Ответ

0 голосов
/ 21 декабря 2018

ассоциативный массив нельзя использовать в SQL.Если вы используете выражение, подобное массиву (индексу), в SQL, то фактически движок PL / SQL получает значение по индексу, а затем результат привязывается к движку SQL до выполнения оператора SQL .

* 1006.* Более конкретно
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 .test('GBP') в коде PL / SQL передается как переменная связывания 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.
...