2016-12-07 2 views
0

У меня есть таблица TVL_DETAIL, содержащая столбец TVL_CD_LIST. Колонка TVL_CD_LIST содержит три записи:
TVL_CD_LIST:
M1180_Z6827
K5900_Z6828
I2510Разделительные значения с разделителями Использование REGEXP_SUPSTR в Oracle 10g

Я использовал следующий код в попытке вернуть только значение (так, исключая подчеркивание):

SELECT 
TVL_CD_LIST 
FROM TVL_DETAIL 
WHERE TVL_CD_LIST IN (SELECT regexp_substr(TVL_CD_LIST,'[^_]+', 1, level) FROM DUAL 
CONNECT BY regexp_substr(TVL_CD_LIST,'[^_]+', 1, level) IS NOT NULL) 

Что я ожидал увидеть в отдельных рядах:
M1180
Z6827
K5900
Z6828
I2510

Но это только возвращает I2510 (что исходное значение, которое не содержит подчеркивание).

Что я делаю неправильно? Любая помощь приветствуется. Благодаря!

ответ

0

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

Примечание: Объяснение того, почему при разборе строки, используя форму регулярных выражений '[^_]+' плохо здесь: https://stackoverflow.com/a/31464699/2543416

Вы хотите, чтобы разобрать список, выбирая элементы:

SQL> with TVL_DETAIL(TVL_CD_LIST) as (
    select 'M1180_Z6827' from dual union 
    select 'K5900_Z6828' from dual union 
    select 'I2510' from dual 
    ) 
    SELECT distinct regexp_substr(TVL_CD_LIST, '(.*?)(_|$)', 1, level, NULL, 1) element 
    FROM TVL_DETAIL 
    CONNECT BY level <= LENGTH(regexp_replace(TVL_CD_LIST, '[^_]', '')) + 1; 
    -- 11g CONNECT BY level <= regexp_count(TVL_CD_LIST, '_') + 1; 

ELEMENT 
----------- 
Z6827 
K5900 
M1180 
I2510 
Z6828 

SQL> 

И это здорово, если вы хотите для отслеживания строки и элемента внутри строки:

SQL> with TVL_DETAIL(row_nbr, TVL_CD_LIST) as (
    select 1, 'M1180_Z6827' from dual union 
    select 2, 'K5900_Z6828' from dual union 
    select 3, 'I2510' from dual 
    ) 
    SELECT row_nbr, column_value substring_nbr, 
      regexp_substr(TVL_CD_LIST, '(.*?)(_|$)', 1, column_value, NULL, 1) element 
    FROM TVL_DETAIL, 
    TABLE(
     CAST(
     MULTISET(SELECT LEVEL 
        FROM dual 
        CONNECT BY level <= LENGTH(regexp_replace(TVL_CD_LIST, '[^_]', '')) + 1 
        -- 11g CONNECT BY LEVEL <= REGEXP_COUNT(TVL_CD_LIST, '_')+1 
       ) AS sys.OdciNumberList 
      ) 
    ) 
    order by row_nbr, substring_nbr; 

    ROW_NBR SUBSTRING_NBR ELEMENT 
---------- ------------- ----------- 
     1    1 M1180 
     1    2 Z6827 
     2    1 K5900 
     2    2 Z6828 
     3    1 I2510 

SQL> 

EDIT: к сожалению, отредактированный для работы с 10g как REGEXP_COUNT не доступен до 11g.

+0

Благодаря Gary_W ... так что, когда я выполнить запрос, я получаю эту ошибка: ORA-00939: слишком много аргументов для функции – user3666552

+0

Проверьте синтаксис тщательно, как вы может видеть, что это сработало для меня. –

0

Запроса вы использовали создает список, но вы сравниваете список записей с колонкой это сам, используя пункт in, как таковой M1180 или Z6827 не может быть равны M1180_Z6827 и поэтому для K5900_Z6828. I2510 имеет только одно значение, чтобы оно соответствовало.

Вы можете использовать нижеследующий запрос, если ваше требование именно то, что вы упоминали в своем желаемом выходе.

SQL> WITH tvl_detail AS 
     2 (SELECT 'M1180_Z6827' tvl_cd_list FROM dual 
     3 UNION ALL 
     4 SELECT 'K5900_Z6828' FROM dual 
     5 UNION ALL 
     6 SELECT 'I2510' FROM dual) 
     7 --------------------------- 
     8 --- End of data preparation 
     9 --------------------------- 
    10 SELECT regexp_substr(tvl_cd_list, '[^_]+', 1, LEVEL) AS tvl_cd_list 
    11 FROM tvl_detail 
    12 CONNECT BY regexp_substr(tvl_cd_list, '[^_]+', 1, LEVEL) IS NOT NULL 
    13   AND PRIOR tvl_cd_list = tvl_cd_list 
    14   AND PRIOR sys_guid() IS NOT NULL; 

ВЫВОД:

TVL_CD_LIST 
-------------------------------------------- 
I2510 
K5900 
Z6828 
M1180 
Z6827