Как передать несколько значений в один параметр в хранимой процедуре (Oracle) - PullRequest
1 голос
/ 01 апреля 2020

У меня есть параметр, созданный для хранимой процедуры, который позволяет пользователю передавать несколько входов.

create procedure sp1 (p1 in varchar2)
as
begin
 select proc_id from proc_tbl where proc_id in (p1);
end;

Пользователь ожидает ввода нескольких значений, разделенных запятой или пробелом, таких как a1, b2, c3 в п. 1 Все PROC_ID, хранящиеся в proc_tbl, находятся в верхнем регистре.

SP не запустился успешно и принимает входные данные как целую строку.

В обычном sql в предложении мы можем просто напечатайте вот так

select proc_id from proc_tbl where proc_id in ('A1', 'B2', 'C3')

Как мы можем применить тот же лог c в oracle sp без учета регистра?

Ответы [ 4 ]

0 голосов
/ 02 апреля 2020

Если у вас есть контроль над параметрами, было бы надежнее использовать коллекцию вместо списка через запятую в строке. Вы можете создать свою собственную коллекцию или использовать одну из готовых коллекций.

Схема

--drop table proc_tbl;
create table proc_tbl(proc_id number);
insert into proc_tbl values(1);
insert into proc_tbl values(2);
insert into proc_tbl values(3);

Процедура

--SYS.ODCINUMBERLIST is defind as a VARRAY(32767) OF NUMBER.
--Or you could create your own type, like: create type number_tab as table of number;
create or replace procedure sp1 (p1 in sys.odcinumberlist) as
    v_count number;
begin
    select count(*)
    into v_count
    from proc_tbl
    where proc_id in (select column_value from table(p1));

    dbms_output.put_line('Count: '||v_count);
end;
/

Пример вызова

begin
    sp1(sys.odcinumberlist(1,2));
end;
/

Result
------
Count: 2
0 голосов
/ 01 апреля 2020

С точки зрения инъекции SQL вы, вероятно, захотите взять некоторый тип коллекции в качестве параметра. Или, по крайней мере, отсканируйте ввод на наличие слов. Но после этого вы можете просто использовать свою строку как часть Dynami c SQL следующим образом:

create procedure sp1 (p1 in varchar2)
as
  TYPE lt_ResultTable is TABLE OF proc_table.proc_id%TYPE;
  l_tResult lt_ResultTable;
  l_nResult proc_table.proc_id%type;
begin
 EXECUTE IMMEDIATE 'select proc_id from proc_tbl where proc_id in ('||p1||')'
  BULK COLLECT INTO l_tResult;
 /*If you are guaranteed only one row will return from your query, you don't need to use a 
  nested table 
 EXECUTE IMMEDIATE 'select proc_id from proc_tbl where proc_id in ('||p1||')' INTO l_nResult;
*/
end;

0 голосов
/ 01 апреля 2020

Простой выбор без предложения INTO даже не компилируется. Однако есть способ безопасно передать несколько значений в одном аргументе:

create or replace procedure sp1(p1 in varchar2) is
begin
for r in (
    select xt.proc_id
    from proc_tbl pt, xmltable(p1 columns proc_id varchar2(100) path '.') xt
    where pt.proc_id = xt.proc_id
)
loop
    dbms_output.put_line(r.proc_id);
end loop;
end;
/
0 голосов
/ 01 апреля 2020

С точки зрения базы данных, список csv, который задается в качестве аргумента, является просто другой строкой, а не списком значений. Таким образом, вы не можете использовать IN.

Один простой подход использует функцию регулярного выражения:

select proc_id from proc_tbl where regexp_like(p1, '^|,' || proc_id || ',|$', 'i');

Регулярное выражение означает:

  • proc_id в начале строки параметра (^) или перед ней стоит запятая
  • AND: proc_id находится в конце строки параметра ($) или сопровождается запятой
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...