REGEXP_SUBSTR с отрицательной позицией

У меня есть запрос на обработку запятой как разделителя в строке. Я хочу заменить последнее вхождение.

пример: строка: a, b, c, d строка: e, f, g, h, i, j

select regexp_substr(string, '[^,]+', -1, 1)
from dual;

должно вернуть: d и j

но в сообщении об ошибке говорится, что позиция -1 выходит за пределы допустимого диапазона.

Документ Oracle: https://docs.oracle.com/cd/E11882_01/olap.112/e23381/row_functions063.htm#OLAXS456


person dozel    schedule 17.02.2017    source источник
comment
Что с пробелами в первой строке? Если запятая является истинным разделителем, то последняя лексема из первой строки образца будет ' d' (строка длины два: пробел и буква d).   -  person mathguy    schedule 17.02.2017
comment
Я могу принять строку с пробелом.   -  person dozel    schedule 17.02.2017
comment
Опубликованные вами ссылки на документацию относятся к Oracle OLAP, отдельному продукту, отличному от базы данных Oracle. Если у вас установлен Oracle OLAP (что бы это ни значило, я понятия не имею), вы можете расширить функциональность до regexp_substr и других функций, но это не имеет отношения к базе данных Oracle. Документация regexp_substr для стандартного Oracle SQL не допускает отрицательной позиции.   -  person mathguy    schedule 17.02.2017
comment
Подтверждено. Спасибо   -  person dozel    schedule 17.02.2017


Ответы (4)


SELECT regexp_substr(string, '[^,]*$') FROM t

Тест

person Mihai    schedule 17.02.2017
comment
Это работает, но что, если я хочу получить последнее второе вхождение. Проблема в том, что в документации Oracle специально упоминается использование отрицательного int, функция будет искать в обратном направлении. Интересно, почему это не работает. цитата из оракула: «Ненулевое целое число, указывающее символ source_char, с которого функция начинает поиск. Когда позиция отрицательна, функция считает и ищет в обратном направлении от конца строки. Значение position по умолчанию равно 1, что означает, что функция начинает поиск с первого символа source_char.' - person dozel; 17.02.2017
comment
@dozel - в документах Oracle говорится, что это должно быть положительное целое число. 'position — положительное целое число, указывающее символ source_char, с которого Oracle должен начать поиск. Значение по умолчанию равно 1, что означает, что Oracle начинает поиск с первого символа source_char.' - person BriteSponge; 17.02.2017
comment
@dozel — это страница документации 11g — docs.oracle.com/cd/B28359_01/server.111/b28286/ - person BriteSponge; 17.02.2017
comment
@Mihai docs.oracle.com/cd/E18283_01/olap. 112/e17122/ - person dozel; 17.02.2017
comment
@dozel Я никогда не видел отрицательной позиции, либо документы неверны, либо кто-то знает больше, чем я. - person Mihai; 17.02.2017
comment
@Mihai - см. мой комментарий под исходным постом. Oracle OLAP — это не то же самое, что Oracle Database. - person mathguy; 17.02.2017
comment
Подтверждено. Спасибо - person dozel; 17.02.2017

Вот несколько способов, которыми вы можете это сделать:

WITH sample_data AS (SELECT 'a, b, c, d' str FROM dual UNION ALL
                     SELECT 'e, f, g, h, i, j' str FROM dual UNION ALL
                     SELECT 'e, f, g, h, i, jk' str FROM dual UNION ALL
                     SELECT 'e,f,g,h,i,jk' str FROM dual UNION ALL
                     SELECT 'e,f,g,h,i,' str FROM dual UNION ALL
                     SELECT 'e, f, g, h, i,' str FROM dual)
SELECT str,
       ltrim(SUBSTR(str, INSTR(str, ',', -1, 1) + 1)) last_item1,
       regexp_substr(str, '.*, ?([^,]*$)', 1, 1, NULL, 1) last_item3
FROM   sample_data;

STR               LAST_ITEM1        LAST_ITEM3
----------------- ----------------- -----------------
a, b, c, d        d                 d
e, f, g, h, i, j  j                 j
e, f, g, h, i, jk jk                jk
e,f,g,h,i,jk      jk                jk
e,f,g,h,i,                          
e, f, g, h, i,                      

Это жеребьевка между обоими вариантами относительно того, какой из них будет наиболее производительным и / или удобным в обслуживании в вашей системе - вам нужно это проверить.

Приведенное выше решение regexp_substr проверяет шаблон любого символа (кроме новой строки), за которым следует запятая, затем пробел (или нет) и, наконец, любой символ, который не является запятой, до конца строки. Затем мы выводим 1-е подвыражение (которое определяется заключенной в скобки частью шаблона).

Я включил ltrim в элемент substr/instr, поскольку вы сказали, что ваш разделитель — запятая, но, похоже, это была запятая + пробел.

person Boneist    schedule 17.02.2017
comment
Я думаю, что мой вопрос больше о том, почему использование -1 в качестве позиции не работает, в то время как в документе оракула специально говорится, что мы можем использовать отрицательный int, если мы хотим выполнять поиск в обратном направлении. Я могу поиграться с substr и instr, но зачем мне это, если есть гораздо более простой способ. - person dozel; 17.02.2017
comment
Это потому, что документация, которую вы просматривали (которая имеет старый формат и, следовательно, в любом случае может быть устаревшей), похоже, содержит ошибку. У вас не может быть отрицательных чисел ни в позиции, ни в повторении в REGEXP_SUBSTR. - person Boneist; 17.02.2017
comment
более новый документ говорит то же самое: (docs.oracle. com/cd/E11882_01/olap.112/e23381/). Но, возможно, вы правы, у документа есть недостатки. - person dozel; 17.02.2017
comment
@dozel - не путайте Oracle OLAP (отдельный продукт) со стандартным Oracle SQL (базой данных Oracle)! - person mathguy; 17.02.2017
comment
@Boneist - я спросил ОП, и он / она ответил, что запятая является настоящим разделителем; пробелы, если они есть, должны быть сохранены. (Или все в порядке, если они сохраняются.) Если это так, почти наверняка решения, использующие стандартные строковые функции, а не регулярные выражения, будут более эффективными. - person mathguy; 17.02.2017

Решение без регулярного выражения может быть:

select substr(string, instr( string, ',', -1)+1)
from yourTable

Здесь вы используете instr, чтобы найти последнее вхождение ',', если оно есть, а затем substr, чтобы вернуть только необходимую часть входной строки.

person Aleksej    schedule 17.02.2017

Вы спросили в комментарии, что, если вы хотите получить второе вхождение? Четвертый аргумент — это элемент, который вы хотите вернуть. Этот формат обрабатывает элементы NULL:

with tbl(str) as (
  select 'a, b, c, d' from dual union
  select 'e,,g,h,i,j' from dual
)
select regexp_substr(str, '(.*?)(,|$)', 1, 2, NULL, 1) element
from tbl; 
person Gary_W    schedule 17.02.2017