Комментарии 9
Использую обычно чуть другой вариант
SELECT regexp_substr(masks, '[^,]+', 1, level) val from dual
CONNECT BY instr(masks, ',', 1, level - 1) > 0
Хорошая гимнастика для ума, конечно, но ещё более отличный пример того как делать не надо. Чем (в итоге) цикл-то не устроил?
Я посоветовался с коллегой, и мы решили, что в нашем конкретном случае скорость выполнения не критична. Поэтому я оставил вариант с CONNECT BY и регулярными выражениями, так как читаемость лучше. В отдельную функцию выносить не стал, так как разбор больших последовательностей не так часто встречается.
Если мне требуется просто вычленить 2-3 значения из строки, то обычно я пользуюсь регулярными выражениями:
Отвечая конкретно на Ваш вопрос «Чем цикл не устроил?», цикл меня устраивал, просто хотелось сделать более простым способом. Не ожидал, что этот «простой» способ окажется настолько медленнее.
Если мне требуется просто вычленить 2-3 значения из строки, то обычно я пользуюсь регулярными выражениями:
v_str := '02/2018/AAAA' || '/';
v_strA := regexp_substr(v_str, '[^/]+', 1, 1);
v_strB := regexp_substr(v_str, '[^/]+', 1, 2);
v_strC := regexp_substr(v_str, '[^/]+', 1, 3);
Отвечая конкретно на Ваш вопрос «Чем цикл не устроил?», цикл меня устраивал, просто хотелось сделать более простым способом. Не ожидал, что этот «простой» способ окажется настолько медленнее.
Раньше тоже использовал такой способ, но недавно в недрах Apexa был найден пакет, который работает заметно быстрее.
Сначала создаются типы:
Затем функция:
И потом очень удобно использовать в запросах:
Сначала создаются типы:
create or replace type TypeObject as object
(
val varchar2(4000)
);
create or replace type TypeList as table of TypeObject;
Затем функция:
create or replace function F_EXT_SUBSTR(str in clob,ch in varchar2) return TypeList pipelined is
v_path APEX_APPLICATION_GLOBAL.VC_ARR2;
BEGIN
v_path := APEX_UTIL.STRING_TO_TABLE(str, ch);
for i in v_path.first..v_path.last loop
pipe row (TypeObject(v_path(i)));
end loop;
exception when others then
null;
end;
И потом очень удобно использовать в запросах:
select val from table(f_ext_substr('100,200,300,400,500',','))
Оо, спасибо.
Оказывается в Oracle всё таки есть функция, разбивающая строку на подстроки, хоть и возвращает она коллекцию.
Конкретно Ваш вариант мне не совсем подходит, так как у нас правило: не создавать лишний раз коллекцию на уровне схемы.
Насколько я знаю функция TABLE() работает только с объектами, объявленными на уровне схемы.
Оказывается в Oracle всё таки есть функция, разбивающая строку на подстроки, хоть и возвращает она коллекцию.
Конкретно Ваш вариант мне не совсем подходит, так как у нас правило: не создавать лишний раз коллекцию на уровне схемы.
Насколько я знаю функция TABLE() работает только с объектами, объявленными на уровне схемы.
да, TABLE() весьма прихотлив к объектам.
Я думаю, для такой функции стоит сделать исключение, так как она используется очень часто
Я думаю, для такой функции стоит сделать исключение, так как она используется очень часто
Можно не менять v_str
v_str := SUBSTR(v_str, INSTR(v_str, ',', 1) + 1);
а изменять start_position в INSTR
v_str := SUBSTR(v_str, INSTR(v_str, ',', 1) + 1);
а изменять start_position в INSTR
У Вас лишний nvl и проверка на неравенство в connect by. Достаточно так:
CONNECT BY regexp_instr(str, '[^,]+', 1, level) > 0
Зарегистрируйтесь на Хабре, чтобы оставить комментарий
Разбиение строки по разделителю. Немного про CONNECT BY