#sql #oracle #oracle12c
#sql #Oracle #oracle12c
Вопрос:
У меня есть таблица с именем ‘config’, и когда я запрашиваю ее следующим образом:
SELECT value FROM config WHERE property = 'SPECIAL_STORE_ID'
его ответ будет: 59216;131205;76707;167206
//... (1)
Я хочу обозначить вышеуказанные значения, используя точку с запятой в качестве разделителя, а затем использовать их в операторе пользовательской функции IF
для сравнения, что-то вроде этого:
IF in_store_id exists in (<delimited response from (1) above>)//...(2)
THEN do some stuff
где in_store_id
находится параметр, переданный функции
Возможно ли это сделать как однострочное в (2) выше?
Я на Oracle 12c
Ответ №1:
Однострочный? Я так не думаю, но — если вас устраивает что-то подобное, хорошо.
SQL> select * From config;
VALUE PROPERTY
-------------- ----------------
7369;7499;7521 SPECIAL_STORE_ID
SQL> declare
2 in_store_id varchar2(20) := 7369;
3 l_exists number;
4 begin
5 select instr(value, ';' || in_store_id || ';')
6 into l_exists
7 from config
8 where property = 'SPECIAL_STORE_ID';
9
10 if l_exists > 0 then
11 dbms_output.put_line('that STORE_ID exists in the value');
12 else
13 dbms_output.put_line('that STORE_ID does not exist in the value');
14 end if;
15 end;
16 /
that STORE_ID exists in the value
PL/SQL procedure successfully completed.
SQL>
Комментарии:
1. Если я не ошибаюсь, это будет работать некорректно в случае, когда
in_store_id
будет только часть некоторого идентификатора внутриvalue
likein_store_id
is1
иvalue
is123;456;789
.regexp_instr(value, '(^|;)'||in_store_id||'(;|$)')
может быть лучшим выбором2. Вы также можете избежать регулярных выражений, добавив разделитель с обеих сторон строки и выполнив поиск ‘;myval;’. Если производительность является требованием, то, очевидно, модель данных нуждается в пересмотре
3. Спасибо вам обоим. Исправлено, строка # 5.
4. @AndrewSayer хороший момент, но все равно не будет работать, если идентификатор является первым или последним в значении. Однако должно работать, если оба
value
иin_store_id
будут обернуты разделителем с обеих сторон
Ответ №2:
Если ответ с разделителями является коллекцией, вы можете использовать member of
для проверки, содержит ли коллекция идентификатор или нет, как
create or replace procedure test_procedure2(p_property in varchar2, p_id in varchar2) is
type test_t is table of varchar2(20);
l_ids test_t;
begin
select regexp_substr(value, '[^;] ', 1, level) bulk collect into l_ids
from (select value from config where property = p_property)
connect by level <= regexp_count(value, ';') 1;
if(p_id member of (l_ids)) then
dbms_output.put_line('Do stuff for '||p_property||' '||p_id);
end if;
end;
/
или сделайте это без сбора с промежуточным выбором, например
create or replace procedure test_procedure1(p_property in varchar2, p_id in varchar2) is
l_flag number(3);
begin
select count(1) into l_flag from dual where p_id in (
select regexp_substr(value, '[^;] ', 1, level)
from (select value from config where property = p_property)
connect by level <= regexp_count(value, ';') 1
);
if(l_flag > 0) then
dbms_output.put_line('Do stuff for '||p_property||' '||p_id);
end if;
end;
/
См. fiddle
Комментарии:
1. Спасибо за ваш ответ. Мне пришлось гуглить
connect by
, чтобы узнать, что это такое 🙂 -узнал кое-что классное. Ответ Литтлфута менее сложный — я соглашусь с этим2. Конечно, я также нахожу ответ Литтлфута более кратким в случае, когда вам просто нужно проверить, представлен ли идентификатор в строке или нет. По какой-то причине я просто решил, что вам также нужно иметь возможность маркировать строку для некоторых других целей