Sql удалить дубликаты из строки, разделенной запятыми

Я хочу сделать запрос на sql-сервере, который может сделать следующий вывод, как столбец _B из столбца_A. Столбцы имеют тип varchar.

  Column_A                                 column_B
  karim,karim,rahim,masud,raju,raju        karim,rahim,masud,raju
  jon,man,jon,kamal,kamal                  jon,man,kamal
  c,abc,abc,pot                            c,abc,pot

person Biddut    schedule 19.03.2018    source источник
comment
Никогда не храните данные в виде элементов, разделенных запятыми. Это только доставит вам массу неприятностей.   -  person jarlh    schedule 19.03.2018
comment
Исправьте свою структуру данных, чтобы она была более совместима с реляционными базами данных. Тогда реструктуризация будет намного проще.   -  person Gordon Linoff    schedule 19.03.2018
comment
Почему в первой строке нужно отбросить рахим в столбце Б?   -  person Joe Taras    schedule 19.03.2018
comment
Спасибо, я отредактировал.   -  person Biddut    schedule 19.03.2018
comment
Пример приводит к поиску: sql удалить дубликаты из строки, разделенной запятыми. Первая страница содержит stackoverflow.com/questions/42918548/ и stackoverflow.com/questions/20882509/   -  person Dan D.    schedule 19.03.2018


Ответы (2)


Прежде всего: Вам уже сказали в комментариях, что это очень плохой дизайн (нарушающий 1.NF)! Если у вас есть хоть малейший шанс изменить это, вам действительно следует... Никогда не храните более одного значения в одной ячейке!

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

Это самый простой подход, который я могу придумать: преобразовать CSV в XML и вызвать XQuery-функцию distinct-values()

DECLARE @tbl TABLE(ColumnA VARCHAR(MAX));
INSERT INTO @tbl VALUES
 ('karim,karim,rahim,masud,raju,raju')
,('jon,man,jon,kamal,kamal')
,('c,abc,abc,pot');

WITH Splitted AS
(
    SELECT ColumnA 
          ,CAST('<x>' + REPLACE(ColumnA,',','</x><x>') + '</x>' AS XML) AS TheParts
    FROM @tbl 
)
SELECT ColumnA
      ,TheParts.query('distinct-values(/x/text())').value('.','varchar(250)') AS ColumnB
FROM Splitted;

Результат

ColumnA                             ColumnB
karim,karim,rahim,masud,raju,raju   karim rahim masud raju
jon,man,jon,kamal,kamal             jon man kamal
c,abc,abc,pot                       c abc pot

ОБНОВЛЕНИЕ Держите запятые

WITH Splitted AS
(
    SELECT ColumnA 
          ,CAST('<x>' + REPLACE(ColumnA,',','</x><x>') + '</x>' AS XML) AS TheParts
    FROM @tbl 
)
SELECT ColumnA
      ,STUFF(
          (TheParts.query
          ('
          for $x in distinct-values(/x/text())
            return <x>{concat(",", $x)}</x>
          ').value('.','varchar(250)')),1,1,'') AS ColumnB
FROM Splitted;

Результат

ColumnB
karim,rahim,masud,raju
jon,man,kamal
c,abc,pot
person Shnugo    schedule 19.03.2018
comment
не было бы проще использовать ЗАМЕНУ, чтобы вернуть запятую? что-то вроде этого? REPLACE(TheParts.query('различные-значения(/x/text())').value('.','varchar(250)') , ' ' , ',') AS ColumnB ? - person hkravitz; 19.03.2018
comment
@hkravitz Ну, если бы значения могли включать пробелы, это поставило бы запятые в плохие места ... Я часто надеялся на возможность передать разделитель таким функциям XQuery (то же самое с data()). Но по умолчанию это всегда пробел. .. - person Shnugo; 19.03.2018

SQL remove duplicates from comma separated string:

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

drop function if exists remove_duplicates_from_comma_separated_string(text);

CREATE or replace FUNCTION remove_duplicates_from_comma_separated_string(arg1 text) 
RETURNS text language plpgsql AS $$ declare 
  item text;  
  split_items text[];  
  ret_items text[];  
  ret_val text; 
BEGIN 
  --split your string on commas and trim whitespace 
  split_items := string_to_array(ltrim(arg1), ','); 
  --enumerate each item, if it doesn't exist in the new array then add it. 
  FOREACH item IN ARRAY split_items LOOP 
    if ( item::text = ANY(ret_items)) then 
    else 
        --append this unique item into ret_items 
        select array_append(ret_items, ltrim(item)) into ret_items; 
    end if;  
  END LOOP; 
  --flatten the final array to a text with comma delimiter 
  SELECT array_to_string(ret_items, ',', '*') into ret_val; 
  return ret_val; 
END; $$;

Итак, теперь мы можем вызвать функцию для таблицы следующим образом:

drop table if exists foo_table; 
create table foo_table(name text); 
insert into foo_table values('karim,karim,rahim,masud,raju,raju'); 
insert into foo_table values('jon,man,jon,kamal,kamal'); 
insert into foo_table values('jon,man,kamal'); 
insert into foo_table values('c,abc,poty'); 
insert into foo_table values('c,abc,abc,kotb'); 
select remove_duplicates_from_comma_separated_string(name) from foo_table; 

Что печатает:

┌───────────────────────────────────────────────┐ 
│ remove_duplicates_from_comma_separated_string │ 
├───────────────────────────────────────────────┤ 
│ karim,rahim,masud,raju                        │ 
│ jon,man,kamal                                 │ 
│ jon,man,kamal                                 │ 
│ c,abc,poty                                    │ 
│ c,abc,kotb                                    │ 
└───────────────────────────────────────────────┘ 

Коэффициент запаха кода: 9,5 из 10. Строительная бригада смотрит, как начинающий программист забивает гвоздь трубным ключом за 90 долларов, все закатывают глаза.

person Eric Leschinski    schedule 25.07.2021