REGEX для выбора n-го значения из списка, допускающего нули

Я использую REGEXP_SUBSTR() вернуть n-е значение из списка через запятую. Это прекрасно работает, когда присутствуют все значения, но не работает, если элемент имеет значение null. Вот пример, который работает, когда присутствуют все значения, и я выбираю второе вхождение из 1 или более символов, которые не являются запятыми:

SQL> select REGEXP_SUBSTR('1,2,3,4,5,6', '[^,]+', 1, 2) data
  2  from dual;

D
-
2

Но когда второе значение равно нулю, я действительно получаю третий элемент в списке, что, конечно же, является вторым появлением 1 или более символов, которые не являются запятыми. Однако мне нужно вернуть NULL, так как 2-й элемент пуст:

SQL> select REGEXP_SUBSTR('1,,3,4,5,6', '[^,]+', 1, 2) data
  2  from dual;

D
-
3

Если я изменю регулярное выражение так, чтобы оно содержало ноль или более символов вместо 1 или более, оно также не будет работать для чисел после нуля:

SQL> select REGEXP_SUBSTR('1,,3,4,5,6', '[^,]*', 1, 4) data
  2  from dual;

D
-
3

Мне нужно учесть нулевое значение, но, похоже, не могу понять синтаксис правильно. Логически мне нужно вернуть то, что находится до n-го вхождения запятой, независимо от того, присутствуют данные или нет (и учесть последнее значение также). Есть идеи?

2 ответа

Решение

Спасибо тем, кто ответил. Изучив ваши ответы и ответы по предоставленной ссылке, я пришел к следующему решению:

SQL> select REGEXP_SUBSTR('1,,3,4,5', '(.*?)(,|$)', 1, 2, NULL, 1) data
  2  from dual;

Data
----

Который может быть описан как "посмотрите на 2-е вхождение необязательного набора из нуля или более символов, за которым следует запятая или конец строки, и верните 1-ую подгруппу (которая представляет собой данные без запятой или конца линия).

Я забыл упомянуть, что я тестировал ноль в разных позициях, несколько нулей, выбирая разные позиции и т. Д.

Единственное предостережение, которое я могу найти, это то, что если поле, которое вы ищете, больше доступного числа, оно просто возвращает NULL, поэтому вам нужно знать об этом. Не проблема для моего случая.

РЕДАКТИРОВАТЬ: Я обновляю принятый ответ в интересах будущих искателей, которые могут наткнуться на это.

Следующим шагом является инкапсуляция кода, чтобы он мог быть превращен в более простую, многократно используемую функцию. Вот источник функции:

  FUNCTION  GET_LIST_ELEMENT(string_in VARCHAR2, element_in NUMBER, delimiter_in VARCHAR2 DEFAULT ',') RETURN VARCHAR2 IS
    BEGIN
      RETURN REGEXP_SUBSTR(string_in, '(.*?)(\'||delimiter_in||'|$)', 1, element_in, NULL, 1);
  END GET_LIST_ELEMENT;

Это скрывает сложность регулярных выражений от разработчиков, которым это может быть не совсем удобно, и делает код чище в любом случае при использовании. Назовите это так, чтобы получить 4-й элемент:

select get_list_element('123,222,,432,555', 4) from dual;

Как насчет чего-то такого брутального:

select REGEXP_SUBSTR(replace('1,,3,4,5,6', ',,', ',NULL,'), '[^,]+', 1, 2) data
from dual

Это возвращает строковое значение. Вы можете получить настоящий NULL используя случай:

select (case when REGEXP_SUBSTR(replace('1,,3,4,5,6', ',,', ',NULL,'), '[^,]+', 1, 2) = 'NULL'
             then NULL
             else REGEXP_SUBSTR(replace('1,,3,4,5,6', ',,', ',NULL,'), '[^,]+', 1, 2)
        end)
from dual;

Там может быть regexp_Единственное решение, но это то, что первым приходит на ум.

Другие вопросы по тегам