Удаление дубликатов и NULL в спецсимволе String - PullRequest
1 голос
/ 03 апреля 2020

Прежде чем начать свой вопрос, я бы определенно согласился, что это плохой дизайн, и теперь мы пытаемся это исправить. В дальнейшем для всех новых данных мы будем следовать 1NF

--- Вот скрипка ----

У меня есть такие данные таблицы.

enter image description here

Я хочу удалить повторяющиеся значения и 'NULL 'значения.

Ожидаемый результат:

180;;200
AMD;;SRD
ASE;;GIF;;TED
1
AMD;;SRD
null
LKG;;This is text with space

Что я пробовал:

WITH Splitted AS
(

    select id,attr,val
     ,CAST('<x>' + REPLACE(replace(val,'NULL',''),';;','</x><x>') + '</x>' AS XML) AS TheParts
    from test where val like '%;;%' 
)
SELECT 
      Replace(STUFF(
          (TheParts.query
          ('
          for $x in distinct-values(/x/text())
            return <x>{concat(";;", $x)}</x>
          ').value('.','varchar(250)')),1,2,''),' ','') AS ColumnB
FROM Splitted;

Токовый выход

180;;200
AMD;;SRD
ASE;;GIF;;TED;;ASE  --problem here
1
AMD;;SRD
null
LKG;;Thisistextwithspace -- problem here

Я также теряю пространство между строкой. И в некоторых случаях значение повторяется. Я думаю из-за лишних пробелов в конце. Как это исправить? Или есть ли лучший способ добиться этого?

1 Ответ

2 голосов
/ 03 апреля 2020

Поскольку вы используете старую версию сервера SQL, у вас нет доступа к STRING_SPLIT или STRING_AGG. Первый, однако, здесь не особенно полезен, так как Microsoft все еще не реализовали порядковые позиции в функции, и она поддерживает только разделитель одного символа.

Вместо этого я собираюсь использовать DelimitedSplit8k_LEAD, который поддерживает порядковые позиции. К сожалению, он также поддерживает только разделитель одного символа, поэтому я заменил двойной разделитель точки с запятой (;;) на трубу (|); так как я предполагаю, что они не появятся в ваших данных.

2012 также не имеет TRIM, поэтому вам придется использовать RTRIM и LTRIM для обрезки значений.

Наконец, вы можете использовать «старый» метод FOR XML PATH для «повторного агрегирования» строки:

WITH Splits AS(
    SELECT t.id,
           t.attr,
           DS.ItemNumber,
           NULLIF(LTRIM(RTRIM(DS.Item)),'NULL') AS Item,
           ROW_NUMBER() OVER (PARTITION BY T.id, LTRIM(RTRIM(NULLIF(DS.Item,'NULL'))) ORDER BY DS.ItemNumber) AS RN
    FROM dbo.test t
         CROSS APPLY dbo.DelimitedSplit8K_LEAD(REPLACE(t.val,';;','|'),'|') DS) --DelimitedSplit8K only supports a one character splitter
SELECT t.ID,
       t.attr,
       STUFF((SELECT ';;' + S.Item
              FROM Splits S
              WHERE S.ID = t.ID
                AND S.RN = 1
              ORDER BY S.ItemNumber
              FOR XML PATH(''),TYPE).value('.','varchar(MAX)'),1,2,'') AS NewVal
FROM dbo.test t;

Редактировать: Забыли о дубликатах. Я использую ROW_NUMBER в CTE для нумерации значений, а затем фильтрую в WHERE подзапроса FOR XML PATH. DISTINCT и GROUP BY не будут работать там, так как тогда ItemNumber не будет разрешено использовать в ORDER BY.

...