sql >> Base de Datos >  >> RDS >> Sqlserver

eliminar duplicados de coma o cadena de operador de canalización

Enfoque

El siguiente enfoque se puede utilizar para eliminar los duplicados de una lista delimitada de valores.

  1. Use REPLACE() función para convertir diferentes delimitadores en el mismo delimitador.
  2. Use REPLACE() función para inyectar etiquetas XML de cierre y apertura para crear un fragmento XML
  3. Utilice CAST(expr AS XML) función para convertir el fragmento anterior en el tipo de datos XML
  4. Utilice OUTER APPLY para aplicar la función con valores de tabla nodes() para dividir el fragmento XML en sus etiquetas XML constituyentes. Esto devuelve cada etiqueta XML en una fila separada.
  5. Extrae solo el valor de la etiqueta XML usando value() y devuelve el valor utilizando el tipo de datos especificado.
  6. Agregue una coma después del valor mencionado anteriormente.
  7. Tenga en cuenta que estos valores se devuelven en filas separadas. El uso de DISTINCT palabra clave ahora elimina filas duplicadas (es decir, valores).
  8. Utilice FOR XML PATH('') cláusula para concatenar los valores en varias filas en una sola fila.

Consulta

Poniendo el enfoque anterior en forma 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 y resultado

Dada la entrada:

La consulta anterior devolverá el resultado:

Fíjate en la coma final al final. Te lo dejo como ejercicio para eliminar eso.

EDITAR:Recuento de duplicados

OP solicitó en un comentario "¿cómo obtengo el recuento de duplicados también? en una columna separada ".

La forma más sencilla sería usar la consulta anterior pero eliminar la última línea FOR XML PATH('') . Luego, contando todos los valores y valores distintos devueltos por SELECT expresión en la consulta anterior (es decir, PivotedTable.PivotedColumn.value('.','nvarchar(max)') ). La diferencia entre el recuento de todos los valores y el recuento de valores distintos es el recuento 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 la misma entrada que se muestra arriba, el resultado de esta consulta es:

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