Как удалить дубликаты из списка, разделенного запятыми, с помощью regexp_replace в Oracle?

я имею

 POW,POW,POWPRO,PRO,PRO,PROUTL,TNEUTL,TNEUTL,UTL,UTLTNE,UTL,UTLTNE

я хочу

POW,POWPRO,PRO,PROUTL,TNEUTL,UTL,UTLTNE

Я старался

select regexp_replace('POW,POW,POWPRO,PRO,PRO,PROUTL,TNEUTL,TNEUTL,UTL,UTLTNE,UTL,UTLTNE','([^,]+)(,\1)+','\1') from dual

И я получаю вывод

 POWPROUTL,TNEUTL,UTLTNE,UTLTNE

Но я хочу, чтобы результат был

POW,POWPRO,PRO,PROUTL,TNEUTL,UTL,UTLTNE

Пожалуйста помоги.

 MT023 июн. 2016 г., 23:40
Возможная копия предыдущего вопроса ФП:Различия значений CSV с использованием REGEXP_REPLACE в оракуле
 MT024 июн. 2016 г., 00:17
Это будет соответствовать всем дубликатам(?<=,|^)([^,]+),(?=(?:[^,]+,)*\1(?:,|$)) но Oracle не поддерживает прогнозирование в регулярных выражениях.

Ответы на вопрос(2)

отает с любой возможной входной строкой и удаляет дубликаты на месте - он сохраняет порядок входных токенов, каким бы он ни был. Он также удаляет последовательные запятые (он «удаляет нули» из входной строки), одновременно обрабатывая нулевые входы. Обратите внимание на вывод для входной строки, состоящей только из запятых, и правильную обработку «токенов», состоящих из двух пробелов и одного пробела соответственно.

Запрос выполняется относительно медленно; если производительность является проблемой, ее можно переписать как рекурсивный запрос, используя «tradit, ional»substr а такжеinstr которые немного быстрее, чем регулярные выражения.

with inputs (input_string) as (
       select 'POW,POW,POWPRO,PRO,PRO,PROUTL,TNEUTL,TNEUTL,UTL,UTLTNE,UTL,UTLTNE' from dual
       union all
       select null from dual
       union all
       select 'ab,ab,st,ab,st,  , ,  ,x,,,r' from dual
       union all
       select ',,,' from dual
     ),
     tokens (input_string, rk, token) as (
       select     input_string, level, 
                  regexp_substr(input_string, '([^,]+)', 1, level, null, 1)
       from       inputs 
       connect by level <= 1 + regexp_count(input_string, ',')
     ),
     distinct_tokens (input_string, rk, token) as (
       select     input_string, min(rk) as rk, token
       from       tokens
       group by   input_string, token
     )
select   input_string, listagg(token, ',') within group (order by rk) output_string
from     distinct_tokens
group by input_string
;

Результаты для входов, которые я создал:

INPUT_STRING                                                       OUTPUT_STRING
------------------------------------------------------------------ ----------------------------------------
,,,                                                                (null)
POW,POW,POWPRO,PRO,PRO,PROUTL,TNEUTL,TNEUTL,UTL,UTLTNE,UTL,UTLTNE  POW,POWPRO,PRO,PROUTL,TNEUTL,UTL,UTLTNE
ab,ab,st,ab,st,  , ,  ,x,,,r                                       ab,st,  , ,x,r
(null)                                                             (null)


4 rows selected.

которые используют только SQL, и третье решение, которое использует небольшую / простую функцию PL / SQL, которая делает очень короткий окончательный запрос SQL.

Установка Oracle:

CREATE TABLE data ( value ) AS
SELECT 'POW,POW,POWPRO,PRO,PRO,PROUTL,TNEUTL,TNEUTL,UTL,UTLTNE,UTL,UTLTNE' FROM DUAL;

CREATE TYPE stringlist AS TABLE OF VARCHAR2(4000);
/

Запрос 1:

SELECT LISTAGG( t.COLUMN_VALUE, ',' ) WITHIN GROUP ( ORDER BY t.COLUMN_VALUE ) AS list
FROM   data d,
       TABLE(
         SET(
           CAST(
             MULTISET(
              SELECT REGEXP_SUBSTR( d.value, '[^,]+', 1, LEVEL )
              FROM   DUAL
              CONNECT BY LEVEL <= REGEXP_COUNT( d.value, '[^,]+' )
             ) AS stringlist
           )
         )
       ) t
GROUP BY d.value;

Выходы:

LIST
---------------------------------------
POW,POWPRO,PRO,PROUTL,TNEUTL,UTL,UTLTNE

Запрос 2:

SELECT ( SELECT LISTAGG(  COLUMN_VALUE, ',' ) WITHIN GROUP ( ORDER BY ROWNUM )
         FROM TABLE( d.uniques ) ) AS list
FROM   (
  SELECT ( SELECT CAST(
                    COLLECT(
                      DISTINCT
                      REGEXP_SUBSTR( d.value, '[^,]+', 1, LEVEL )
                    )
                    AS stringlist
                  )
            FROM  DUAL
            CONNECT BY LEVEL <= REGEXP_COUNT( d.value, '[^,]+' )
         ) uniques
  FROM   data d
) d;

Выход:

LIST
---------------------------------------
POW,POWPRO,PRO,PROUTL,TNEUTL,UTL,UTLTNE

Установка Oracle:

Небольшая вспомогательная функция:

CREATE FUNCTION split_String(
  i_str    IN  VARCHAR2,
  i_delim  IN  VARCHAR2 DEFAULT ','
) RETURN stringlist DETERMINISTIC
AS
  p_result       stringlist := stringlist();
  p_start        NUMBER(5) := 1;
  p_end          NUMBER(5);
  c_len CONSTANT NUMBER(5) := LENGTH( i_str );
  c_ld  CONSTANT NUMBER(5) := LENGTH( i_delim );
BEGIN
  IF c_len > 0 THEN
    p_end := INSTR( i_str, i_delim, p_start );
    WHILE p_end > 0 LOOP
      p_result.EXTEND;
      p_result( p_result.COUNT ) := SUBSTR( i_str, p_start, p_end - p_start );
      p_start := p_end + c_ld;
      p_end := INSTR( i_str, i_delim, p_start );
    END LOOP;
    IF p_start <= c_len + 1 THEN
      p_result.EXTEND;
      p_result( p_result.COUNT ) := SUBSTR( i_str, p_start, c_len - p_start + 1 );
    END IF;
  END IF;
  RETURN p_result;
END;
/

Запрос 3:

SELECT ( SELECT LISTAGG(  COLUMN_VALUE, ',' ) WITHIN GROUP ( ORDER BY ROWNUM )
         FROM TABLE( SET( split_String( d.value ) ) ) ) AS list
FROM   data d;

или (если вы хотите передать только одно значение):

SELECT LISTAGG(  COLUMN_VALUE, ',' ) WITHIN GROUP ( ORDER BY ROWNUM ) AS list
FROM   TABLE( SET( split_String(
          'POW,POW,POWPRO,PRO,PRO,PROUTL,TNEUTL,TNEUTL,UTL,UTLTNE,UTL,UTLTNE'
       ) ) );

Выход:

LIST
---------------------------------------
POW,POWPRO,PRO,PROUTL,TNEUTL,UTL,UTLTNE
 prashant thakre24 июн. 2016 г., 03:24
Если вы можете создать таблицу и вставить значения, тогда любой сможет выполнить это требование, однако я думаю, что вы должны ответить, не создавая таблицу.
 MT024 июн. 2016 г., 03:34
@prashantthakre Посмотритередактировать № 4 если вам нужна версия без создания таблиц - существование (или отсутствие) таблицы практически не имеет значения для решения.

Ваш ответ на вопрос