¿Cómo puedo eliminar filas duplicadas?


1285

¿Cuál es la mejor manera de eliminar filas duplicadas de una SQL Servertabla bastante grande (es decir, más de 300,000 filas)?

Las filas, por supuesto, no serán duplicados perfectos debido a la existencia del RowIDcampo de identidad.

Mi mesa

RowID int not null identity(1,1) primary key,
Col1 varchar(20) not null,
Col2 varchar(2048) not null,
Col3 tinyint not null

13
Consejo rápido para los usuarios de PostgreSQL que leen esto (muchos, según la frecuencia con la que está vinculado): Pg no expone los términos CTE como vistas actualizables, por lo que no puede DELETE FROMun término CTE directamente. Ver stackoverflow.com/q/18439054/398670
Craig Ringer el

@CraigRinger lo mismo es cierto para Sybase : he recopilado las soluciones restantes aquí (también debería ser válido para PG y otros: stackoverflow.com/q/19544489/1855801 (simplemente reemplace la ROWID()función por la columna RowID, si corresponde)
maf-soft

12
Solo para agregar una advertencia aquí. Cuando ejecute cualquier proceso de desduplicación, ¡siempre verifique primero lo que está eliminando! Esta es una de esas áreas donde es muy común eliminar accidentalmente buenos datos.
Jeff Davis

Respuestas:


1142

Suponiendo que no hay GROUP BYvalores nulos, las columnas únicas y SELECTel MIN (or MAX)RowId como la fila para mantener. Luego, simplemente elimine todo lo que no tenía una ID de fila:

DELETE FROM MyTable
LEFT OUTER JOIN (
   SELECT MIN(RowId) as RowId, Col1, Col2, Col3 
   FROM MyTable 
   GROUP BY Col1, Col2, Col3
) as KeepRows ON
   MyTable.RowId = KeepRows.RowId
WHERE
   KeepRows.RowId IS NULL

En caso de que tenga un GUID en lugar de un entero, puede reemplazar

MIN(RowId)

con

CONVERT(uniqueidentifier, MIN(CONVERT(char(36), MyGuidColumn)))

327
¿Funcionaría esto también? DELETE FROM MyTable WHERE RowId NOT IN (SELECT MIN(RowId) FROM MyTable GROUP BY Col1, Col2, Col3);
Georg Schölly

10
@Andriy - En SQL Server LEFT JOINes menos eficiente que NOT EXISTS sqlinthewild.co.za/index.php/2010/03/23/... El mismo sitio también compara NOT INvs NOT EXISTS. sqlinthewild.co.za/index.php/2010/02/18/not-exists-vs-not-in De los 3, creo que NOT EXISTSfunciona mejor. Los tres generarán un plan con una unión automática, aunque eso se puede evitar.
Martin Smith

12
@ Martin, @ Georgia: Entonces, hice una pequeña prueba. Se creó una tabla grande y se rellenó como se describe aquí: sqlinthewild.co.za/index.php/2010/03/23/… Luego se produjeron dos SELECT, uno con la técnica LEFT JOIN + WHERE IS NULL y el otro con NOT En uno. Luego procedí con los planes de ejecución, ¿y adivina qué? Los costos de la consulta fueron del 18% para la IZQUIERDA IZQUIERDA contra el 82% para NO ENTRADA, una gran sorpresa para mí. Podría haber hecho algo que no debería haber hecho o viceversa, lo cual, de ser cierto, me gustaría saber.
Andriy M

16
@ GeorgSchölly ha proporcionado una respuesta elegante. Lo he usado en una tabla donde un error de PHP mío creó filas duplicadas.
Philip Kearns

12
Lo siento, pero ¿por qué es DELETE MyTable FROM MyTablela sintaxis correcta? No veo poner el nombre de la tabla justo después del DELETEcomo una opción en la documentación aquí . Lo siento si esto es obvio para los demás; Soy un novato en SQL tratando de aprender. Más importante que por qué funciona: ¿cuál es la diferencia entre incluir el nombre de la tabla allí o no?
levininja el

760

Otra posible forma de hacerlo es

; 

--Ensure that any immediately preceding statement is terminated with a semicolon above
WITH cte
     AS (SELECT ROW_NUMBER() OVER (PARTITION BY Col1, Col2, Col3 
                                       ORDER BY ( SELECT 0)) RN
         FROM   #MyTable)
DELETE FROM cte
WHERE  RN > 1;

Estoy usando lo ORDER BY (SELECT 0)anterior, ya que es arbitrario qué fila conservar en caso de empate.

Para conservar el último en RowIDorden, por ejemplo, podría usarORDER BY RowID DESC

Planes de ejecucion

El plan de ejecución para esto es a menudo más simple y más eficiente que el de la respuesta aceptada, ya que no requiere la autounión.

Planes de ejecucion

Esto no es siempre el caso, sin embargo. Un lugar donde se GROUP BYpodría preferir la solución son las situaciones en las que se elegiría un agregado de hash en lugar de un agregado de flujo.

La ROW_NUMBERsolución siempre dará el mismo plan, mientras que la GROUP BYestrategia es más flexible.

Planes de ejecucion

Los factores que podrían favorecer el enfoque agregado de hash serían

  • No hay índice útil en las columnas de partición
  • relativamente menos grupos con relativamente más duplicados en cada grupo

En las versiones extremas de este segundo caso (si hay muy pocos grupos con muchos duplicados en cada uno), también se podría considerar simplemente insertar las filas para mantenerlas en una nueva tabla, luego TRUNCATEcopiar el original y copiarlo de nuevo para minimizar el registro en comparación con eliminar un Muy alta proporción de las filas.


28
Si puedo agregar: La respuesta aceptada no funciona con las tablas que usa uniqueidentifier. Este es mucho más simple y funciona perfectamente en cualquier mesa. Gracias martin
BrunoLM

15
¡Esta es una respuesta increíble! Funcionó cuando eliminé el viejo PK antes de darme cuenta de que había duplicados. +100
Mikael Eliasson

12
Sugiero preguntar y luego responder esta pregunta (con esta respuesta) en DBA.SE. Luego podemos agregarlo a nuestra lista de respuestas canónicas .
Nick Chammas

16
A diferencia de la respuesta aceptada, esto también funcionó en una tabla que no tenía clave ( RowId) para comparar.
vossad01

8
Este no funciona en todas las versiones del servidor SQL, por otro lado
David

150

Hay un buen artículo sobre la eliminación de duplicados en el sitio de soporte de Microsoft. Es bastante conservador: hacen que hagas todo en pasos separados, pero debería funcionar bien en tablas grandes.

He usado autouniones para hacer esto en el pasado, aunque probablemente podría ser mejorado con una cláusula HAVING:

DELETE dupes
FROM MyTable dupes, MyTable fullTable
WHERE dupes.dupField = fullTable.dupField 
AND dupes.secondDupField = fullTable.secondDupField 
AND dupes.uniqueField > fullTable.uniqueField

¡Perfecto! descubrí que esta es la forma más eficiente de eliminar filas duplicadas en mi versión anterior de mariadb 10.1.xx. ¡gracias!
Borracho M

¡Mucho más simple y más fácil de entender!
Marc

98

La siguiente consulta es útil para eliminar filas duplicadas. La tabla en este ejemplo tiene IDcomo columna de identidad y las columnas que tienen datos duplicados son Column1, Column2y Column3.

DELETE FROM TableName
WHERE  ID NOT IN (SELECT MAX(ID)
                  FROM   TableName
                  GROUP  BY Column1,
                            Column2,
                            Column3
                  /*Even if ID is not null-able SQL Server treats MAX(ID) as potentially
                    nullable. Because of semantics of NOT IN (NULL) including the clause
                    below can simplify the plan*/
                  HAVING MAX(ID) IS NOT NULL) 

El uso de secuencias de comandos siguientes espectáculos de GROUP BY, HAVING, ORDER BYen una consulta y devuelve los resultados con la columna duplicado y su recuento.

SELECT YourColumnName,
       COUNT(*) TotalCount
FROM   YourTableName
GROUP  BY YourColumnName
HAVING COUNT(*) > 1
ORDER  BY COUNT(*) DESC 

1
Error de MySQL con el primer script 'No puede especificar la tabla de destino' TableName 'para actualizar en la cláusula FROM'
D.Rosado

Además del error que D.Rosado ya informó, su primera consulta también es muy lenta. La consulta SELECT correspondiente tomó mi configuración + - 20 veces más que la respuesta aceptada.
parvus

8
@parvus: la pregunta está etiquetada como SQL Server, no MySQL. La sintaxis está bien en SQL Server. También MySQL es notoriamente malo en la optimización de subconsultas, ver por ejemplo aquí . Esta respuesta está bien en SQL Server. De hecho, a NOT INmenudo funciona mejor que OUTER JOIN ... NULL. Agregaría un HAVING MAX(ID) IS NOT NULLa la consulta aunque, aunque semánticamente, no debería ser necesario, ya que eso puede mejorar el ejemplo del
Martin Smith

2
Funciona muy bien en PostgreSQL 8.4.
2014

63
delete t1
from table t1, table t2
where t1.columnA = t2.columnA
and t1.rowid>t2.rowid

Postgres:

delete
from table t1
using table t2
where t1.columnA = t2.columnA
and t1.rowid > t2.rowid

¿Por qué publicar una solución de Postgres en una pregunta de SQL Server?
Lankymart

2
@Lankymart Porque los usuarios de postgres también vendrán aquí. Mira el puntaje de esta respuesta.
Gabriel

2
He visto esto en algunas preguntas populares de SQL, como aquí , aquí y aquí . El OP obtuvo su respuesta y todos los demás también recibieron ayuda. No hay problema en mi humilde opinión.
Gabriel

44
DELETE LU 
FROM   (SELECT *, 
               Row_number() 
                 OVER ( 
                   partition BY col1, col1, col3 
                   ORDER BY rowid DESC) [Row] 
        FROM   mytable) LU 
WHERE  [row] > 1 

1
Recibo este mensaje en azure SQL DW: una cláusula FROM actualmente no es compatible con una declaración DELETE.
Amit

40

Esto eliminará filas duplicadas, excepto la primera fila

DELETE
FROM
    Mytable
WHERE
    RowID NOT IN (
        SELECT
            MIN(RowID)
        FROM
            Mytable
        GROUP BY
            Col1,
            Col2,
            Col3
    )

Consulte ( http://www.codeproject.com/Articles/157977/Remove-Duplicate-Rows-from-a-Table-in-SQL-Server )


10
Para mysql dará error: Código de error: 1093. No puede especificar la tabla de destino 'Mytable' para actualizar en la cláusula FROM. pero este pequeño cambio funcionará para mysql: ELIMINAR DE Mytable DONDE RowID NO IN (SELECCIONE ID DE (SELECCIONE MIN (RowID) COMO ID DE Mytable GROUP BY Col1, Col2, Col3) COMO TEMP)
Ritesh

35

Preferiría CTE para eliminar filas duplicadas de la tabla del servidor sql

recomiendo seguir este artículo :: http://codaffection.com/sql-server-article/delete-duplicate-rows-in-sql-server/

manteniendo original

WITH CTE AS
(
SELECT *,ROW_NUMBER() OVER (PARTITION BY col1,col2,col3 ORDER BY col1,col2,col3) AS RN
FROM MyTable
)

DELETE FROM CTE WHERE RN<>1

sin guardar original

WITH CTE AS
(SELECT *,R=RANK() OVER (ORDER BY col1,col2,col3)
FROM MyTable)
 
DELETE CTE
WHERE R IN (SELECT R FROM CTE GROUP BY R HAVING COUNT(*)>1)

24

Para obtener filas duplicadas:

SELECT
name, email, COUNT(*)
FROM 
users
GROUP BY
name, email
HAVING COUNT(*) > 1

Para eliminar las filas duplicadas:

DELETE users 
WHERE rowid NOT IN 
(SELECT MIN(rowid)
FROM users
GROUP BY name, email);      

Para los usuarios de MySQL, tenga en cuenta que, en primer lugar, tiene que ser DELETE FROM, en segundo lugar, no funcionará, porque no puede hacerlo SELECTdesde la misma tabla de la que DELETEproviene. En MySQL esto despega MySQL error 1093.
Íhor Mé

23

Rápido y sucio para eliminar filas duplicadas exactas (para tablas pequeñas):

select  distinct * into t2 from t1;
delete from t1;
insert into t1 select *  from t2;
drop table t2;

3
Tenga en cuenta que la pregunta en realidad especifica la duplicación no exacta (debido al id. De fila).
Dennis Jaheruddin

21

Prefiero la solución subquery \ having count (*)> 1 a la combinación interna porque me resultó más fácil de leer y fue muy fácil convertirla en una instrucción SELECT para verificar qué se eliminaría antes de ejecutarla.

--DELETE FROM table1 
--WHERE id IN ( 
     SELECT MIN(id) FROM table1 
     GROUP BY col1, col2, col3 
     -- could add a WHERE clause here to further filter
     HAVING count(*) > 1
--)

No elimina todos los registros que aparecen en la consulta interna. Necesitamos eliminar solo duplicados y preservar el original.
Sandy

3
Solo está devolviendo el que tiene la ID más baja, según el min (id) en la cláusula select.
James Errico

2
Descomente la primera, segunda y última línea de la consulta.
James Errico

77
Esto no limpiará todos los duplicados. Si tiene 3 filas que son duplicadas, solo seleccionará la fila con el MIN (id) y eliminará esa, dejando dos filas restantes que son duplicadas.
Chloe

2
Sin embargo, terminé usando esta declaración repetida una y otra vez, para que realmente progresara en lugar de que la conexión se agotara o la computadora se apagara. Lo cambié a MAX(id)para eliminar los últimos duplicados, y lo agregué LIMIT 1000000a la consulta interna para que no tuviera que escanear toda la tabla. Esto mostró un progreso mucho más rápido que las otras respuestas, que parecerían bloquearse durante horas. Después de podar la tabla a un tamaño manejable, puede finalizar con las otras consultas. Consejo: asegúrese de que col1 / col2 / col3 tenga índices para agrupar por.
Chloe

17
SELECT  DISTINCT *
      INTO tempdb.dbo.tmpTable
FROM myTable

TRUNCATE TABLE myTable
INSERT INTO myTable SELECT * FROM tempdb.dbo.tmpTable
DROP TABLE tempdb.dbo.tmpTable

55
Truncar no funcionará si tiene referencias de clave externa a myTable.
Sameer Alibhai

15

Pensé en compartir mi solución, ya que funciona en circunstancias especiales. En mi caso, la tabla con valores duplicados no tenía una clave externa (porque los valores se duplicaron de otra base de datos).

begin transaction
-- create temp table with identical structure as source table
Select * Into #temp From tableName Where 1 = 2

-- insert distinct values into temp
insert into #temp 
select distinct * 
from  tableName

-- delete from source
delete from tableName 

-- insert into source from temp
insert into tableName 
select * 
from #temp

rollback transaction
-- if this works, change rollback to commit and execute again to keep you changes!!

PD: cuando trabajo en cosas como esta, siempre uso una transacción, esto no solo garantiza que todo se ejecute en su conjunto, sino que también me permite probar sin arriesgar nada. Pero, por supuesto, deberías hacer una copia de seguridad de todos modos solo para estar seguro ...


14

Esta consulta mostró muy buen rendimiento para mí:

DELETE tbl
FROM
    MyTable tbl
WHERE
    EXISTS (
        SELECT
            *
        FROM
            MyTable tbl2
        WHERE
            tbl2.SameValue = tbl.SameValue
        AND tbl.IdUniqueValue < tbl2.IdUniqueValue
    )

eliminó 1M de filas en poco más de 30 segundos de una tabla de 2M (50% de duplicados)


14

Usando CTE. La idea es unirse en una o más columnas que formen un registro duplicado y luego eliminar lo que desee:

;with cte as (
    select 
        min(PrimaryKey) as PrimaryKey
        UniqueColumn1,
        UniqueColumn2
    from dbo.DuplicatesTable 
    group by
        UniqueColumn1, UniqueColumn1
    having count(*) > 1
)
delete d
from dbo.DuplicatesTable d 
inner join cte on 
    d.PrimaryKey > cte.PrimaryKey and
    d.UniqueColumn1 = cte.UniqueColumn1 and 
    d.UniqueColumn2 = cte.UniqueColumn2;

1
Creo que te estás perdiendo un AND en tu JOIN.
Justin R.

13

Otra solución fácil se puede encontrar en el enlace pegado aquí . Éste es fácil de entender y parece ser efectivo para la mayoría de los problemas similares. Sin embargo, es para SQL Server, pero el concepto utilizado es más que aceptable.

Estas son las partes relevantes de la página vinculada:

Considere estos datos:

EMPLOYEE_ID ATTENDANCE_DATE
A001    2011-01-01
A001    2011-01-01
A002    2011-01-01
A002    2011-01-01
A002    2011-01-01
A003    2011-01-01

Entonces, ¿cómo podemos eliminar esos datos duplicados?

Primero, inserte una columna de identidad en esa tabla utilizando el siguiente código:

ALTER TABLE dbo.ATTENDANCE ADD AUTOID INT IDENTITY(1,1)  

Use el siguiente código para resolverlo:

DELETE FROM dbo.ATTENDANCE WHERE AUTOID NOT IN (SELECT MIN(AUTOID) _
    FROM dbo.ATTENDANCE GROUP BY EMPLOYEE_ID,ATTENDANCE_DATE) 

1
"Fácil de entender", "parece ser efectivo", pero ni una palabra sobre en qué consiste el método. Imagínense que el enlace se vuelve inválido, ¿de qué sirve saber que el método fue fácil de entender y efectivo? Considere agregar partes esenciales de la descripción del método en su publicación, de lo contrario, esta no es una respuesta.
Andriy M

Este método es útil para tablas donde aún no tiene una identidad definida. ¡A menudo necesita deshacerse de los duplicados para definir la clave primaria!
Jeff Davis

@JeffDavis: la ROW_NUMBERversión funciona bien para ese caso sin necesidad de agregar una nueva columna antes de comenzar.
Martin Smith

12

Aquí hay otro buen artículo sobre la eliminación de duplicados .

Discute por qué es difícil: " SQL se basa en álgebra relacional, y los duplicados no pueden ocurrir en álgebra relacional, porque los duplicados no están permitidos en un conjunto. "

La solución de la tabla temporal y dos ejemplos de mysql.

En el futuro, lo evitará a nivel de base de datos o desde la perspectiva de una aplicación. Sugeriría el nivel de la base de datos porque su base de datos debería ser responsable de mantener la integridad referencial, los desarrolladores solo causarán problemas;)


1
SQL se basa en conjuntos múltiples. Pero incluso si se basara en conjuntos, estas dos tuplas (1, a) y (2, a) son diferentes.
Andrew

12

Oh, por supuesto. Usa una tabla temporal. Si desea una declaración única, no muy eficaz que "funcione", puede ir con:

DELETE FROM MyTable WHERE NOT RowID IN
    (SELECT 
        (SELECT TOP 1 RowID FROM MyTable mt2 
        WHERE mt2.Col1 = mt.Col1 
        AND mt2.Col2 = mt.Col2 
        AND mt2.Col3 = mt.Col3) 
    FROM MyTable mt)

Básicamente, para cada fila de la tabla, la sub-selección encuentra el RowID superior de todas las filas que son exactamente como la fila en consideración. Entonces terminas con una lista de RowID que representan las filas "originales" no duplicadas.


11

Tenía una tabla donde necesitaba preservar filas no duplicadas. No estoy seguro de la velocidad o la eficiencia.

DELETE FROM myTable WHERE RowID IN (
  SELECT MIN(RowID) AS IDNo FROM myTable
  GROUP BY Col1, Col2, Col3
  HAVING COUNT(*) = 2 )

77
Esto supone que hay como máximo 1 duplicado.
Martin Smith

¿Por qué no HAVING COUNT(*) > 1?
Philipp M

11

Utilizar este

WITH tblTemp as
(
SELECT ROW_NUMBER() Over(PARTITION BY Name,Department ORDER BY Name)
   As RowNumber,* FROM <table_name>
)
DELETE FROM tblTemp where RowNumber >1

10

La otra forma es crear una nueva tabla con los mismos campos y con índice único . Luego mueva todos los datos de la tabla anterior a la nueva tabla . SQL Server automáticamente ignora (también hay una opción sobre qué hacer si habrá un valor duplicado: ignorar, interrumpir o algo) valores duplicados. Entonces tenemos la misma tabla sin filas duplicadas. Si no desea un índice único, después de la transferencia de datos puede soltarlo .

Especialmente para tablas más grandes , puede usar DTS (paquete SSIS para importar / exportar datos) para transferir todos los datos rápidamente a su nueva tabla indexada de forma única. Para 7 millones de filas, solo lleva unos minutos.


9

Al utilizar la consulta a continuación, podemos eliminar registros duplicados basados ​​en la columna única o en la columna múltiple. la consulta a continuación se elimina en base a dos columnas. el nombre de la tabla es: testingy los nombres de columnaempno,empname

DELETE FROM testing WHERE empno not IN (SELECT empno FROM (SELECT empno, ROW_NUMBER() OVER (PARTITION BY empno ORDER BY empno) 
AS [ItemNumber] FROM testing) a WHERE ItemNumber > 1)
or empname not in
(select empname from (select empname,row_number() over(PARTITION BY empno ORDER BY empno) 
AS [ItemNumber] FROM testing) a WHERE ItemNumber > 1)

9
  1. Crear una nueva tabla en blanco con la misma estructura.

  2. Ejecute una consulta como esta

    INSERT INTO tc_category1
    SELECT *
    FROM tc_category
    GROUP BY category_id, application_id
    HAVING count(*) > 1
  3. Luego ejecute esta consulta

    INSERT INTO tc_category1
    SELECT *
    FROM tc_category
    GROUP BY category_id, application_id
    HAVING count(*) = 1

9

Esta es la forma más fácil de eliminar registros duplicados

 DELETE FROM tblemp WHERE id IN 
 (
  SELECT MIN(id) FROM tblemp
   GROUP BY  title HAVING COUNT(id)>1
 )

http://askme.indianyouth.info/details/how-to-dumplicate-record-from-table-in-using-sql-105


¿Por qué alguien está votando esto? Si tiene más de dos de la misma identificación, esto NO funcionará. En su lugar, escriba: eliminar de tblemp donde la identificación no está en (seleccione min (id) del grupo de tblemp por título)
crellee

7

Mencionaría este enfoque, así como puede ser útil, y funciona en todos los servidores SQL: a menudo solo hay uno: dos duplicados, y se conocen los ID y el recuento de duplicados. En este caso:

SET ROWCOUNT 1 -- or set to number of rows to be deleted
delete from myTable where RowId = DuplicatedID
SET ROWCOUNT 0

7

Desde el nivel de aplicación (desafortunadamente). Estoy de acuerdo en que la forma correcta de evitar la duplicación es a nivel de la base de datos mediante el uso de un índice único, pero en SQL Server 2005, un índice puede ser de solo 900 bytes, y mi campo varchar (2048) elimina eso.

No sé qué tan bien funcionaría, pero creo que podrías escribir un disparador para hacer cumplir esto, incluso si no pudieras hacerlo directamente con un índice. Algo como:

-- given a table stories(story_id int not null primary key, story varchar(max) not null)
CREATE TRIGGER prevent_plagiarism 
ON stories 
after INSERT, UPDATE 
AS 
    DECLARE @cnt AS INT 

    SELECT @cnt = Count(*) 
    FROM   stories 
           INNER JOIN inserted 
                   ON ( stories.story = inserted.story 
                        AND stories.story_id != inserted.story_id ) 

    IF @cnt > 0 
      BEGIN 
          RAISERROR('plagiarism detected',16,1) 

          ROLLBACK TRANSACTION 
      END 

Además, varchar (2048) me suena sospechoso (algunas cosas en la vida son 2048 bytes, pero es bastante raro); ¿Realmente no debería ser varchar (max)?


7

Otra forma de hacer esto: -

DELETE A
FROM   TABLE A,
       TABLE B
WHERE  A.COL1 = B.COL1
       AND A.COL2 = B.COL2
       AND A.UNIQUEFIELD > B.UNIQUEFIELD 

¿Qué es diferente a esta respuesta existente del 20 de agosto de 2008? - stackoverflow.com/a/18934/692942
Lankymart

7
DELETE
FROM
    table_name T1
WHERE
    rowid > (
        SELECT
            min(rowid)
        FROM
            table_name T2
        WHERE
            T1.column_name = T2.column_name
    );

Hola, Teena, te has perdido la tabla Alice nombre T1 después del comentario de eliminación; de lo contrario, se producirá una excepción de sintaxis.
Nagaraj M

6
CREATE TABLE car(Id int identity(1,1), PersonId int, CarId int)

INSERT INTO car(PersonId,CarId)
VALUES(1,2),(1,3),(1,2),(2,4)

--SELECT * FROM car

;WITH CTE as(
SELECT ROW_NUMBER() over (PARTITION BY personid,carid order by personid,carid) as rn,Id,PersonID,CarId from car)

DELETE FROM car where Id in(SELECT Id FROM CTE WHERE rn>1)

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.