repetir - sql eliminar registros duplicados menos uno
¿Cómo puedo eliminar filas duplicadas en una tabla? (13)
¿Puedes agregar un campo de identidad de clave principal a la tabla?
Tengo una mesa con decir 3 columnas. No hay una clave principal, por lo que puede haber filas duplicadas. Necesito solo guardar uno y borrar los otros. ¿Alguna idea de cómo hacer esto es Sql Server?
Agregue una columna de identidad para que actúe como una clave primaria sustituta y utilícela para identificar dos de las tres filas que se eliminarán.
Consideraría dejar la columna de identidad en su lugar después, o si esta es una especie de tabla de enlaces, cree una clave primaria compuesta en las otras columnas.
Aquí hay otra manera, con datos de prueba
create table #table1 (colWithDupes1 int, colWithDupes2 int)
insert into #table1
(colWithDupes1, colWithDupes2)
Select 1, 2 union all
Select 1, 2 union all
Select 2, 2 union all
Select 3, 4 union all
Select 3, 4 union all
Select 3, 4 union all
Select 4, 2 union all
Select 4, 2
select * from #table1
set rowcount 1
select 1
while @@rowcount > 0
delete #table1 where 1 < (select count(*) from #table1 a2
where #table1.colWithDupes1 = a2.colWithDupes1
and #table1.colWithDupes2 = a2.colWithDupes2
)
set rowcount 0
select * from #table1
Después de limpiar el desorden actual, puede agregar una clave principal que incluya todos los campos de la tabla. eso evitará que te metas en el lío de nuevo. Por supuesto, esta solución podría romper el código existente. Eso tendrá que ser manejado también.
Esta es una situación difícil. Sin conocer su situación particular (tamaño de la tabla, etc.), creo que lo mejor que puede hacer es agregar una columna de identidad, rellenarla y luego eliminarla. Puede eliminar la columna más tarde, pero le sugiero que la guarde, ya que es realmente bueno tenerla en la mesa.
Manrico Corazzi: me especializo en Oracle, no en MS SQL, así que tendrás que decirme si esto es posible como un impulso en el rendimiento:
- Deje lo mismo que su primer paso: inserte valores distintos en la TABLA2 de TABLA1.
- Suelta TABLE1. (Drop debería ser más rápido que eliminar, supongo, tanto como truncar es más rápido que eliminar).
- Cambie el nombre de TABLE2 como TABLE1 (le ahorra tiempo, ya que cambia el nombre de un objeto en lugar de copiar datos de una tabla a otra).
No estoy seguro de si esto funciona con instrucciones DELETE, pero esta es una forma de encontrar filas duplicadas:
SELECT *
FROM myTable t1, myTable t2
WHERE t1.field = t2.field AND t1.id > t2.id
No estoy seguro de si puede simplemente cambiar el "SELECCIONAR" a un "ELIMINAR" (¿alguien me quiere avisar?) , Pero incluso si no puede hacerlo, podría simplemente convertirlo en una subconsulta.
SELECCIONARÍA DISTINCT las filas y las arrojaría en una tabla temporal, luego soltaría la tabla fuente y volvería a copiar los datos de la temperatura. EDITAR: ahora con fragmento de código!
INSERT INTO TABLE_2
SELECT DISTINCT * FROM TABLE_1
GO
DELETE FROM TABLE_1
GO
INSERT INTO TABLE_1
SELECT * FROM TABLE_2
GO
Esta es una forma de hacerlo con Common Table Expressions, CTE. No implica bucles, ni columnas nuevas ni nada, y no hará que se desencadenen disparadores no deseados (debido a eliminaciones + inserciones).
Inspirado por este artículo .
CREATE TABLE #temp (i INT)
INSERT INTO #temp VALUES (1)
INSERT INTO #temp VALUES (1)
INSERT INTO #temp VALUES (2)
INSERT INTO #temp VALUES (3)
INSERT INTO #temp VALUES (3)
INSERT INTO #temp VALUES (4)
SELECT * FROM #temp
;
WITH [#temp+rowid] AS
(SELECT ROW_NUMBER() OVER (ORDER BY i ASC) AS ROWID, * FROM #temp)
DELETE FROM [#temp+rowid] WHERE rowid IN
(SELECT MIN(rowid) FROM [#temp+rowid] GROUP BY i HAVING COUNT(*) > 1)
SELECT * FROM #temp
DROP TABLE #temp
¿Qué pasa con esta solución?
Primero ejecutas la siguiente consulta:
select ''set rowcount '' + convert(varchar,COUNT(*)-1) + '' delete from MyTable where field='''''' + field +'''''''' + '' set rowcount 0'' from mytable group by field having COUNT(*)>1
Y luego solo tienes que ejecutar el conjunto de resultados devuelto
set rowcount 3 delete from Mytable where field=''foo'' set rowcount 0
....
....
set rowcount 5 delete from Mytable where field=''bar'' set rowcount 0
He manejado el caso cuando solo tiene una columna, pero es bastante fácil adaptar el mismo enfoque antes de una columna. Avísame si quieres que publique el código.
El siguiente ejemplo funciona también cuando su PK es solo un subconjunto de todas las columnas de la tabla.
(Nota: Me gusta el enfoque con la inserción de otra columna de identificación sustituta más. Pero tal vez esta solución también sea útil).
Primero encuentra las filas duplicadas:
SELECT col1, col2, count(*)
FROM t1
GROUP BY col1, col2
HAVING count(*) > 1
Si solo hay unos pocos, puede eliminarlos manualmente:
set rowcount 1
delete from t1
where col1=1 and col2=1
El valor de "rowcount" debe ser n-1 veces el número de duplicados. En este ejemplo, hay 2 puntos embotados, por lo tanto, el recuento de filas es 1. Si obtiene varias filas duplicadas, debe hacer esto para cada clave primaria única.
Si tiene muchos duplicados, copie cada clave una vez en otra tabla:
SELECT col1, col2, col3=count(*)
INTO holdkey
FROM t1
GROUP BY col1, col2
HAVING count(*) > 1
Luego copie las claves, pero elimine las duplicadas.
SELECT DISTINCT t1.*
INTO holddups
FROM t1, holdkey
WHERE t1.col1 = holdkey.col1
AND t1.col2 = holdkey.col2
En tus llaves tienes ahora llaves únicas. Verifica si no obtienes ningún resultado:
SELECT col1, col2, count(*)
FROM holddups
GROUP BY col1, col2
Eliminar los duplicados de la tabla original:
DELETE t1
FROM t1, holdkey
WHERE t1.col1 = holdkey.col1
AND t1.col2 = holdkey.col2
Inserta las filas originales:
INSERT t1 SELECT * FROM holddups
Por cierto y para ser completo: en Oracle hay un campo oculto que podrías usar (rowid):
DELETE FROM our_table
WHERE rowid not in
(SELECT MIN(rowid)
FROM our_table
GROUP BY column1, column2, column3... ;
Qué tal si:
select distinct * into #t from duplicates_tbl
truncate duplicates_tbl
insert duplicates_tbl select * from #t
drop table #t
Este es el método que utilicé cuando hice esta pregunta :
DELETE MyTable
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