Удалить повторяющиеся значения из строки, разделенной запятыми, в Oracle

Мне нужна ваша помощь с функцией regexp_replace. У меня есть таблица, в которой есть столбец для конкатенированных строковых значений, содержащих дубликаты. Как мне их устранить?

Пример:

Ian,Beatty,Larry,Neesha,Beatty,Neesha,Ian,Neesha

Мне нужно, чтобы вывод был

Ian,Beatty,Larry,Neesha

Дубликаты случайны и не в каком-то определенном порядке.

Обновлять--

Вот как выглядит мой стол

ID   Name1   Name2    Name3     
1     a       b         c
1     c       d         a
2     d       e         a
2     c       d          b

Мне нужна одна строка для каждого идентификатора, имеющего разные name1, name2, name3 в одной строке в виде строки, разделенной запятыми.

ID    Name
1     a,c,b,d,c
2     d,c,e,a,b

Я пытался использовать listagg с отдельными, но я не могу удалить дубликаты.


person Cindy    schedule 10.02.2016    source источник
comment
Какая веская причина использовать правильную соединительную таблицу или даже вложенную таблицу, а не список с разделителями-запятыми. Удачи.   -  person Gordon Linoff    schedule 11.02.2016
comment
Это выглядит как обман это   -  person Dave    schedule 11.02.2016
comment
Шаблон отличается и не работает с моими данными. Дубликаты все еще существуют.   -  person Cindy    schedule 11.02.2016


Ответы (3)


Итак, попробуйте это...

([^,]+),(?=.*[A-Za-z],[] ]*\1)
person Dave    schedule 11.02.2016

Я не думаю, что вы можете сделать это только с помощью regexp_replace, если повторяющиеся значения не находятся рядом друг с другом. Один из подходов состоит в том, чтобы разделить значения, удалить дубликаты, а затем снова собрать их вместе.

Обычный метод токенизации строки с разделителями — с regexp_substr и предложением connect by. Использование переменной связывания с вашей строкой, чтобы сделать код немного понятнее:

var value varchar2(100);
exec :value := 'Ian,Beatty,Larry,Neesha,Beatty,Neesha,Ian,Neesha';

select regexp_substr(:value, '[^,]+', 1, level) as value
from dual
connect by regexp_substr(:value, '[^,]+', 1, level) is not null;

VALUE                        
------------------------------
Ian                           
Beatty                        
Larry                         
Neesha                        
Beatty                        
Neesha                        
Ian                           
Neesha                        

Вы можете использовать это как подзапрос (или CTE), получить из него отдельные значения, а затем собрать его с помощью listagg:

select listagg(value, ',') within group (order by value) as value
from (
  select distinct value from (
    select regexp_substr(:value, '[^,]+', 1, level) as value
    from dual
    connect by regexp_substr(:value, '[^,]+', 1, level) is not null
  )
);

VALUE                        
------------------------------
Beatty,Ian,Larry,Neesha       

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

with t42 (id, value) as (
  select 1, 'Ian,Beatty,Larry,Neesha,Beatty,Neesha,Ian,Neesha' from dual
  union all select 2, 'Mary,Joe,Mary,Frank,Joe' from dual
)
select id, listagg(value, ',') within group (order by value) as value
from (
  select distinct id, value from (
    select id, regexp_substr(value, '[^,]+', 1, level) as value
    from t42
    connect by regexp_substr(value, '[^,]+', 1, level) is not null
    and id = prior id
    and prior dbms_random.value is not null
  )
)
group by id;

        ID VALUE                        
---------- ------------------------------
         1 Beatty,Ian,Larry,Neesha       
         2 Frank,Joe,Mary                

Конечно, в этом не было бы необходимости, если бы вы правильно хранили реляционные данные; наличие строки с разделителями в столбце - не очень хорошая идея.

person Alex Poole    schedule 11.02.2016
comment
Я попробую это и дам вам знать... Данные на самом деле не существуют в виде строки с разделителями. Это из нескольких строк на идентификатор, и я использовал listagg, чтобы объединить их в 1 строку на идентификатор. - person Cindy; 11.02.2016
comment
@Cindy, так почему бы вам просто не получить отдельные значения перед вызовом listagg? - person Alex Poole; 11.02.2016

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

>>> names = 'Ian,Beatty,Larry,Neesha,Beatty,Neesha,Ian,Neesha'
>>> deduped_names = ','.join(set(names.split(',')))
>>> print(deduped_names)
Neesha,Ian,Larry,Beatty
person Moses Wynn    schedule 28.08.2020