2008-09-18 15 views

Respuesta

23

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 
+0

esa es la solución más limpia y genérica, dado que tiene el espacio en disco (la frontera final) – tzot

+0

¿No hay forma de hacerlo con una consulta SQL? En realidad eso es –

+1

tres consultas: INSERT INTO table_2 SELECT DISTINCT * FROM table_1 GO CANCELACIÓN de table_1 ir INSERT INTO table_1 SELECT * FROM table_2 IR –

7

Agregue una columna de identidad para actuar como 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 esto es algún tipo de tabla de enlaces, crear una clave primaria compuesta en las otras columnas.

+0

Agregar una columna de identidad definitivamente ayudará. SQL Server generará una columna fantasma para que cada registro sea único, pero no podrá consultar esta columna. La columna de identidad reducirá parte de esa sobrecarga y garantizará la exclusividad. –

2

Ésta es una situación difícil estar en. Sin saber su situación particular (tamaño de la tabla, etc) Creo que su mejor tiro es agregar una columna de identidad, poblarlo y elimine de acuerdo con ella. Puede eliminar la columna más tarde, pero le sugiero que la guarde, ya que es realmente bueno tenerla en la tabla

7

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 Identificación del sustituto más Pero tal vez esta solución es muy útil también)

En primer lugar encontrar las filas duplicadas:

SELECT col1, col2, count(*) 
FROM t1 
GROUP BY col1, col2 
HAVING count(*) > 1 

Si sólo hay pocos, puede eliminarlos manualmente:

set rowcount 1 
delete from t1 
where col1=1 and col2=1 

el valor de "recuento de filas" debe haber 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 usted tiene muchos duplicados, y luego copiar cada tecla una vez en anoher tabla:

SELECT col1, col2, col3=count(*) 
INTO holdkey 
FROM t1 
GROUP BY col1, col2 
HAVING count(*) > 1 

luego copiar las llaves, pero eliminar los duplicados.

SELECT DISTINCT t1.* 
INTO holddups 
FROM t1, holdkey 
WHERE t1.col1 = holdkey.col1 
AND t1.col2 = holdkey.col2 

En sus llaves tiene ahora claves únicas.Compruebe si usted no recibe 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 

insertar las filas originales:

INSERT t1 SELECT * FROM holddups 

por cierto y por la totalidad: En Oracle hay un campo oculto que puede usar (rowid):

DELETE FROM our_table 
WHERE rowid not in 
(SELECT MIN(rowid) 
FROM our_table 
GROUP BY column1, column2, column3... ; 

ver: Microsoft Knowledge Site

+5

Debería haber mencionado que lo obtuvo en el sitio de soporte de Microsoft. http://support.microsoft.com/kb/139444 –

+0

@Tony: eso es correcto. En mi defensa: hice copiar esto en mi wiki de programación local y ya ni siquiera sabía de dónde venía. – Martin

0

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.

-1

no estoy seguro de si esto funciona con instrucciones DELETE, pero esta es una manera de encontrar las filas duplicadas:

SELECT * 
FROM myTable t1, myTable t2 
WHERE t1.field = t2.field AND t1.id > t2.id 

No estoy seguro de si sólo se puede cambiar el "SELECT" a un " BORRAR "(¿alguien me quiere avisar?), pero incluso si no puede, puede hacerlo en una subconsulta.

4

Este es el método que utiliza when I asked this question -

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 
0

Se puede añadir un campo de identidad de clave principal a la tabla?

0

Manrico Corazzi - Me especializarse en Oracle, MS SQL no, por lo que tiene que decirme si esto es posible, ya que un aumento de rendimiento: -

  1. salir de la misma como su primer paso - inserte distinta valores en la TABLA2 de la TABLA1.
  2. Drop TABLE1. (Drop debería ser más rápido que eliminar, supongo, tanto como truncar es más rápido que eliminar).
  3. Cambie el nombre TABLE2 como TABLE1 (le ahorra tiempo, ya que cambia el nombre de un objeto en lugar de copiar datos de una tabla a otra).
0

Ésta es 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 
4

Ésta es una manera de hacerlo con expresiones de tabla comunes, CTE. No implica bucles, ni columnas nuevas ni nada, y no hará que se desencadenen disparadores no deseados (debido a eliminaciones + inserciones).

Inspirado en this article.

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 
+0

Muy agradable. Siempre estoy sorprendido con lo que CTE puede hacer. –

+0

@Jonas - eso, mi amigo, es genial. Y solo resolvió un problema que tuve. ¡Gracias! –

0

¿Qué tal:

select distinct * into #t from duplicates_tbl 

truncate duplicates_tbl 

insert duplicates_tbl select * from #t 

drop table #t 
0

¿Qué pasa con esta solución:

En primer lugar, ejecute 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 sólo hay que ejecutar el resultado devuelto establecer

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 se tiene sólo una columna, pero es bastante fácil de adaptar el mismo enfoque tomore de una columna. Avísame si quieres que publique el código.

Cuestiones relacionadas