Sqlserver
 sql >> Database >  >> RDS >> Sqlserver

rimuovere i duplicati dalla virgola o dalla stringa dell'operatore della pipeline

Approccio

L'approccio seguente può essere utilizzato per deduplicare un elenco di valori delimitato.

  1. Usa REPLACE() funzione per convertire diversi delimitatori nello stesso delimitatore.
  2. Usa REPLACE() funzione per iniettare tag di chiusura e apertura XML per creare un frammento XML
  3. Utilizza CAST(expr AS XML) funzione per convertire il frammento sopra nel tipo di dati XML
  4. Usa OUTER APPLY per applicare la funzione con valori di tabella nodes() per dividere il frammento XML nei suoi tag XML costituenti. Questo restituisce ogni tag XML su una riga separata.
  5. Estrai solo il valore dal tag XML usando value() funzione e restituisce il valore utilizzando il tipo di dati specificato.
  6. Aggiungi una virgola dopo il valore sopra indicato.
  7. Nota che questi valori vengono restituiti su righe separate. L'utilizzo del DISTINCT la parola chiave ora rimuove le righe duplicate (cioè i valori).
  8. Usa FOR XML PATH('') clausola per concatenare i valori su più righe in un'unica riga.

Interroga

Mettendo l'approccio sopra sotto forma di query:

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('') 

Input e risultato

Dato l'input:

La query precedente restituirà il risultato:

Notare la virgola finale alla fine. Lascio a te come esercizio la rimozione.

EDIT:conteggio dei duplicati

OP richiesto in un commento "come ottengo anche il conteggio dei duplicati? in una colonna separata ".

Il modo più semplice sarebbe utilizzare la query precedente ma rimuovere l'ultima riga FOR XML PATH('') . Quindi, contando tutti i valori e i valori distinti restituiti da SELECT espressione nella query precedente (ad esempio PivotedTable.PivotedColumn.value('.','nvarchar(max)') ). La differenza tra il conteggio di tutti i valori e il conteggio dei valori distinti è il conteggio dei valori duplicati.

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) 

Per lo stesso input mostrato sopra, l'output di questa query è:

CountOfAllValues CountOfUniqueValues CountOfDuplicateValues
---------------- ------------------- ----------------------
8                4                   4