Approccio
L'approccio seguente può essere utilizzato per deduplicare un elenco di valori delimitato.
- Usa
REPLACE()
funzione per convertire diversi delimitatori nello stesso delimitatore. - Usa
REPLACE()
funzione per iniettare tag di chiusura e apertura XML per creare un frammento XML - Utilizza
CAST(expr AS XML)
funzione per convertire il frammento sopra nel tipo di dati XML - Usa
OUTER APPLY
per applicare la funzione con valori di tabellanodes()
per dividere il frammento XML nei suoi tag XML costituenti. Questo restituisce ogni tag XML su una riga separata. - Estrai solo il valore dal tag XML usando
value()
funzione e restituisce il valore utilizzando il tipo di dati specificato. - Aggiungi una virgola dopo il valore sopra indicato.
- Nota che questi valori vengono restituiti su righe separate. L'utilizzo del
DISTINCT
la parola chiave ora rimuove le righe duplicate (cioè i valori). - 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