Sqlserver
 sql >> Base de Dados >  >> RDS >> Sqlserver

remover duplicatas da string do operador de vírgula ou pipeline


Abordagem

A abordagem a seguir pode ser usada para desduplicar uma lista delimitada de valores.
  1. Use o REPLACE() função para converter delimitadores diferentes no mesmo delimitador.
  2. Use o REPLACE() função para injetar tags XML de fechamento e abertura para criar um fragmento XML
  3. Use o CAST(expr AS XML) função para converter o fragmento acima no tipo de dados XML
  4. Use OUTER APPLY para aplicar a função com valor de tabela nodes() para dividir o fragmento XML em suas tags XML constituintes. Isso retorna cada tag XML em uma linha separada.
  5. Extraia apenas o valor da tag XML usando o value() função e retorna o valor usando o tipo de dados especificado.
  6. Anexar uma vírgula após o valor mencionado acima.
  7. Observe que esses valores são retornados em linhas separadas. O uso do DISTINCT palavra-chave agora remove linhas duplicadas (ou seja, valores).
  8. 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