PL/SQL-запрос В строке с разделителями-запятыми

Вопрос:

Я разрабатываю приложение в Oracle APEX. У меня есть строка с идентификатором пользователя, который разделен запятой, который выглядит следующим образом:

45,4932,20,19

Эта строка сохраняется как

:P5_USER_ID_LIST

Мне нужен запрос, который найдет всех пользователей, входящих в этот список, мой запрос выглядит так:

SELECT * FROM users u WHERE u.user_id IN (:P5_USER_ID_LIST);

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

SELECT * FROM users u WHERE u.user_id IN (45,4932,20,19);

Кто-нибудь знает, почему это может быть проблемой?

Ответ №1

Переменная привязки связывает значение a, в этом случае строка ’45, 4932,20,19 ‘. Вы можете использовать динамический SQL и конкатенацию, как было предложено Рэнди, но вам нужно быть очень осторожным, чтобы пользователь не смог изменить это значение, иначе у вас возникнет проблема с внедрением SQL.

Более безопасный маршрут заключается в том, чтобы поместить идентификаторы в коллекцию Apex в процессе PL/SQL:

declare
array apex_application_global.vc_arr2;
begin
array := apex_util.string_to_table (:P5_USER_ID_LIST, ',');
apex_collection.create_or_truncate_collection ('P5_ID_COLL');
apex_collection.add_members ('P5_ID_COLL', array);
end;

Затем измените свой запрос на:

SELECT * FROM users u WHERE u.user_id IN
(SELECT c001 FROM apex_collections
WHERE collection_name = 'P5_ID_COLL')

Ответ №2

Более простым решением является использование instr:

SELECT * FROM users u
WHERE instr(',' || :P5_USER_ID_LIST ||',' ,',' || u.user_id|| ',', 1) !=0;

фокусы:

',' || :P5_USER_ID_LIST ||','

чтобы сделать вашу строку ,45,4932,20,19,

',' || u.user_id|| ','

т.е. ,32, и избегать выбора 32 в ,4932,

Ответ №3

Я столкнулся с этой ситуацией несколько раз, и вот что я использовал:

SELECT *
FROM users u
WHERE ','||to_char(:P5_USER_ID_LIST)||',' like '%,'||to_char(u.user_id)||',%'

ive использовал подобный оператор, но вы должны быть немного осторожны с одним аспектом здесь: ваш элемент P5_USER_ID_LIST должен быть “, 45,4932,20,19”, так что, как это будет сравнивать с точным числом “, 45,” “.

При использовании этого, выбор не будет ошибочным, скажем: 5 с 15, 155, 55.

Попробуйте и дайте мне знать, как это происходит;)

Приветствия,
Alex

Ответ №4

Создайте собственный запрос, а не используйте “createQuery/createNamedQuery”

Ответ №5

Причина этого в том, что вы не можете просто привязать список в списке так, как хотите, и почти каждый делает эту ошибку хотя бы один раз, когда они изучают Oracle (и, вероятно, SQL!).

Когда вы связываете строку ’32, 64,128 ‘, она становится таким же, как:

select ...
from t
where t.c1 in ('32,64,128')

В Oracle это совершенно другое:

select ...
from t
where t.c1 in (32,64,128)

Первый пример имеет одно строковое значение в списке, а второе имеет 3 числа в списке. Причина, по которой вы получаете недопустимую ошибку числа, заключается в том, что Oracle пытается отличить строку ’32, 64,128 ‘от числа, которое она не может сделать из-за запятых в строке.

Вариант этого вопроса “как связать список” появился здесь несколько раз недавно.

В общем, и не прибегая к PLSQL, беспокоясь о SQL Injection или не привязывая запрос правильно, вы можете использовать этот трюк:

with bound_inlist
as
(
select
substr(txt,
instr (txt, ',', 1, level  ) + 1,
instr (txt, ',', 1, level+1) - instr (txt, ',', 1, level) -1 )
as token
from (select ','||:txt||',' txt from dual)
connect by level <= length(:txt)-length(replace(:txt,',',''))+1
)
select *
from bound_inlist a, users u
where a.token = u.id;

Ответ №6

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

Ответ №7

Пожалуйста, не используйте: WHERE ‘,’ || to_char (: P5_USER_ID_LIST) || ‘,’ like ‘%,’ || to_char (u.user_id) || ‘,%’, потому что вы заставите полную таблицу сканирование, хотя в таблице пользователей у вас может быть не так много, поэтому влияние будет низким, но с другими таблицами в корпоративной среде это проблема.

EDIT: я собрал script, чтобы продемонстрировать различия между методом регулярных выражений и подобным методом. Не только регулярное выражение, но и гораздо более надежное.

-- Create table
create table CSV_TEST
(
NUM NUMBER not null,
STR VARCHAR2(20)
);


create sequence csv_test_seq;

begin
for j in 1..10 loop
for i in 1..500000 loop
insert into csv_test( num, str ) values ( csv_test_seq.nextval, to_char( csv_test_seq.nextval ));
end loop;
commit;
end loop;
end;
/

-- Create/Recreate primary, unique and foreign key constraints
alter table CSV_TEST
add constraint CSV_TEST_PK primary key (NUM)
using index ;
alter table CSV_TEST
add constraint CSV_TEST_FK unique (STR)
using index;

select sysdate from dual;
select *
from csv_test t
where t.num in ( Select Regexp_Substr('100001, 100002,   100003   ,      100004, 100005','[^,]+', 1, Level) From Dual
Connect By Regexp_Substr('100001, 100002,100003, 100004, 100005', '[^,]+', 1, Level) Is Not Null);
select sysdate from dual;

select *
from csv_test t
where ('%,' || '100001,100002,   100003,  100004  ,100005' || ',%') like '%,' || num || ',%';
select sysdate from dual;
select *
from csv_test t
where t.num in ( Select Regexp_Substr('100001, 100002,   100003   ,      100004, 100005','[^,]+', 1, Level) From Dual
Connect By Regexp_Substr('100001, 100002,100003, 100004, 100005', '[^,]+', 1, Level) Is Not Null);
select sysdate from dual;

select *
from csv_test t
where ('%,' || '100001,100002,   100003,  100004  ,100005' || ',%') like '%,' || num || ',%';
select sysdate from dual;

drop table csv_test;
drop sequence csv_test_seq;

Ответ №8

Решение от Тони Эндрюса работает для меня. Процесс должен быть добавлен в “Обработка страницы” → “После отправки” → “Процессы”.

Ответ №9

Как вы Запоминание Идентификаторы пользователя, как String, так что вы можете легко соответствовать строки Использование Like как ниже

SELECT * FROM users u WHERE u.user_id LIKE '%'||(:P5_USER_ID_LIST)||'%'

Например

:P5_USER_ID_LIST  = 45,4932,20,19

Ваш запрос обязательно вернет любой из 1 идентификатора пользователя, который соответствует таблице пользователей

Это, безусловно, решит вашу проблему, наслаждайтесь

Ответ №10

вам нужно будет запустить это как динамический SQL.

создайте всю строку, затем запустите ее динамически.

Оцените статью
TechArks.Ru
Добавить комментарий