Abordagem
A abordagem a seguir pode ser usada para desduplicar uma lista delimitada de valores.
- Use o
REPLACE()
função para converter delimitadores diferentes no mesmo delimitador. - Use o
REPLACE()
função para injetar tags XML de fechamento e abertura para criar um fragmento XML - Use o
CAST(expr AS XML)
função para converter o fragmento acima no tipo de dados XML - Use
OUTER APPLY
para aplicar a função com valor de tabelanodes()
para dividir o fragmento XML em suas tags XML constituintes. Isso retorna cada tag XML em uma linha separada. - Extraia apenas o valor da tag XML usando o
value()
função e retorna o valor usando o tipo de dados especificado. - Anexar uma vírgula após o valor mencionado acima.
- Observe que esses valores são retornados em linhas separadas. O uso do
DISTINCT
palavra-chave agora remove linhas duplicadas (ou seja, valores). - Use o
FOR XML PATH('')
cláusula para concatenar os valores em várias linhas em uma única linha.
Consulta
Colocando a abordagem acima no formulário de consulta:
SELECT DISTINCT PivotedTable.PivotedColumn.value('.','nvarchar(max)') + ','
FROM (
-- This query returns the following in theDataXml column:
-- <tag>test1</tag><tag>test2</tag><tag>test1</tag><tag>test2</tag><tag>test3</tag><tag>test4</tag><tag>test4</tag><tag>test4</tag>
-- i.e. it has turned the original delimited data into an XML fragment
SELECT
DataTable.DataColumn AS DataRaw
, CAST(
'<tag>'
-- First replace commas with pipes to have only a single delimiter
-- Then replace the pipe delimiters with a closing and opening tag
+ replace(replace(DataTable.DataColumn, ',','|'), '|','</tag><tag>')
-- Add a final set of closing tags
+ '</tag>'
AS XML) AS DataXml
FROM ( SELECT 'test1,test2,test1|test2,test3|test4,test4|test4' AS DataColumn) AS DataTable
) AS x
OUTER APPLY DataXml.nodes('tag') AS PivotedTable(PivotedColumn)
-- Running the query without the following line will return the data in separate rows
-- Running the query with the following line returns the rows concatenated, i.e. it returns:
-- test1,test2,test3,test4,
FOR XML PATH('')
Entrada e resultado
Dada a entrada:
A consulta acima retornará o resultado:
Observe a vírgula à direita no final. Vou deixar como exercício para você remover isso.
EDIT:contagem de duplicatas
OP solicitado em um comentário "como faço para obter a contagem de duplicatas também? em uma coluna separada ".
A maneira mais simples seria usar a consulta acima, mas remover a última linha
FOR XML PATH('')
. Então, contando todos os valores e valores distintos retornados pelo SELECT
expressão na consulta acima (ou seja, PivotedTable.PivotedColumn.value('.','nvarchar(max)')
). A diferença entre a contagem de todos os valores e a contagem de valores distintos é a contagem de valores duplicados. SELECT
COUNT(PivotedTable.PivotedColumn.value('.','nvarchar(max)')) AS CountOfAllValues
, COUNT(DISTINCT PivotedTable.PivotedColumn.value('.','nvarchar(max)')) AS CountOfUniqueValues
-- The difference of the previous two counts is the number of duplicate values
, COUNT(PivotedTable.PivotedColumn.value('.','nvarchar(max)'))
- COUNT(DISTINCT PivotedTable.PivotedColumn.value('.','nvarchar(max)')) AS CountOfDuplicateValues
FROM (
-- This query returns the following in theDataXml column:
-- <tag>test1</tag><tag>test2</tag><tag>test1</tag><tag>test2</tag><tag>test3</tag><tag>test4</tag><tag>test4</tag><tag>test4</tag>
-- i.e. it has turned the original delimited data into an XML fragment
SELECT
DataTable.DataColumn AS DataRaw
, CAST(
'<tag>'
-- First replace commas with pipes to have only a single delimiter
-- Then replace the pipe delimiters with a closing and opening tag
+ replace(replace(DataTable.DataColumn, ',','|'), '|','</tag><tag>')
-- Add a final set of closing tags
+ '</tag>'
AS XML) AS DataXml
FROM ( SELECT 'test1,test2,test1|test2,test3|test4,test4|test4' AS DataColumn) AS DataTable
) AS x
OUTER APPLY DataXml.nodes('tag') AS PivotedTable(PivotedColumn)
Para a mesma entrada mostrada acima, a saída desta consulta é:
CountOfAllValues CountOfUniqueValues CountOfDuplicateValues
---------------- ------------------- ----------------------
8 4 4