2012-06-21 28 views
5

Cometí un error en un script de inserción masiva, por lo que ahora tengo filas "duplicadas" con diferentes colX. Necesito eliminar estas filas duplicadas, pero no puedo entender cómo. Para ser más precisos, tengo esto:Eliminar filas "duplicadas" en SQL Server 2010

col1 | col2 | col3 | colX  
----+---------------------- 
    0 | 1 | 2 | a 
    0 | 1 | 2 | b 
    0 | 1 | 2 | c 
    0 | 1 | 2 | a 
    3 | 4 | 5 | x 
    3 | 4 | 5 | y 
    3 | 4 | 5 | x 
    3 | 4 | 5 | z 

y quiero mantener la primera aparición de cada uno (fila, COLX):

col1 | col2 | col3 | colX  
----+---------------------- 
    0 | 1 | 2 | a 
    3 | 4 | 5 | x 

Gracias por sus respuestas :)

+2

tablas de bases de datos no tienen un concepto de orden consecutivo. ¿Desea ordenar por min (colX) y mantener esas filas? ¿Hay una columna de marca de tiempo en la fila? –

+3

¿Qué versión de SQL Server estás usando? Por lo que sé, no hay SQL Server 2010. –

+0

Si tiene '0 | 1 | 3 | a' en sus datos, ¿debería mantenerse? o debería ser eliminado? –

Respuesta

10

probar el enfoque más simple con el CTE de SQL Server: http://www.sqlfiddle.com/#!3/2d386/2

datos:

CREATE TABLE tbl 
    ([col1] int, [col2] int, [col3] int, [colX] varchar(1)); 

INSERT INTO tbl 
    ([col1], [col2], [col3], [colX]) 
VALUES 
    (0, 1, 2, 'a'), 
    (0, 1, 2, 'b'), 
    (0, 1, 2, 'c'), 
    (0, 1, 2, 'a'), 
    (3, 4, 5, 'x'), 
    (3, 4, 5, 'y'), 
    (3, 4, 5, 'x'), 
    (3, 4, 5, 'z'); 

Solución:

select * from tbl; 

with a as 
(
    select row_number() over(partition by col1 order by col2, col3, colX) as rn 
    from tbl 
) 
delete from a where rn > 1; 

select * from tbl; 

outpu t:

| COL1 | COL2 | COL3 | COLX | 
----------------------------- 
| 0 | 1 | 2 | a | 
| 0 | 1 | 2 | b | 
| 0 | 1 | 2 | c | 
| 0 | 1 | 2 | a | 
| 3 | 4 | 5 | x | 
| 3 | 4 | 5 | y | 
| 3 | 4 | 5 | x | 
| 3 | 4 | 5 | z | 


| COL1 | COL2 | COL3 | COLX | 
----------------------------- 
| 0 | 1 | 2 | a | 
| 3 | 4 | 5 | x | 

O tal vez esto: http://www.sqlfiddle.com/#!3/af826/1

datos:

CREATE TABLE tbl 
    ([col1] int, [col2] int, [col3] int, [colX] varchar(1)); 

INSERT INTO tbl 
    ([col1], [col2], [col3], [colX]) 
VALUES 
    (0, 1, 2, 'a'), 
    (0, 1, 2, 'b'), 
    (0, 1, 2, 'c'), 
    (0, 1, 2, 'a'), 
    (0, 1, 3, 'a'), 
    (3, 4, 5, 'x'), 
    (3, 4, 5, 'y'), 
    (3, 4, 5, 'x'), 
    (3, 4, 5, 'z'); 

Solución:

select * from tbl; 


with a as 
(
    select row_number() over(partition by col1, col2, col3 order by colX) as rn 
    from tbl 
) 
delete from a where rn > 1; 

select * from tbl; 

Salida:

| COL1 | COL2 | COL3 | COLX | 
----------------------------- 
| 0 | 1 | 2 | a | 
| 0 | 1 | 2 | b | 
| 0 | 1 | 2 | c | 
| 0 | 1 | 2 | a | 
| 0 | 1 | 3 | a | 
| 3 | 4 | 5 | x | 
| 3 | 4 | 5 | y | 
| 3 | 4 | 5 | x | 
| 3 | 4 | 5 | z | 

| COL1 | COL2 | COL3 | COLX | 
----------------------------- 
| 0 | 1 | 2 | a | 
| 0 | 1 | 3 | a | 
| 3 | 4 | 5 | x | 
+0

esto lo hizo, muchas gracias –

2

Sugeriría utilizar CTE y leer todos los registros que no son dup en una tabla separada si tiene muchos duplicados. Sin embargo, hay un puesto recomienda seguir: MSDN

+1

Parece que primero mencionó el enfoque sql "CTE", que es el más simple y en la mayoría de los escenarios funciona. –

1

Suponiendo COLX es único (que no es el caso en su ejemplo, a pesar de que usted ha dicho "diferente COLX") se podría usar lo siguiente para eliminar los duplicados:

;with cteDuplicates as 
(
    select 
     *, 
     row_number() over (partition by col1, col2, col3 order by colX) as ID 
    from Duplicates 
) 
delete D from Duplicates D 
    inner join cteDuplicates C on C.colX = D.Colx 
where ID > 1 

(Digamos que su tabla se denomina "duplicados")

Si COLX no es única, añadir una nueva columna uniqueidentifier, insertar valores distintos en ella y luego usar el código anterior al unirse en esa columna en lugar de colX.

2

Si estás bien con sólo mantener el valor mínimo de COLX, usted puede hacer esto:

delete t from t inner join 
    (select min(colx) mincolx, col1, col2, col3 
    from t 
    group by col1, col2, col3 
    having count(1) > 1) as duplicates 
    on (duplicates.col1 = t.col1 
    and duplicates.col2 = t.col2 
    and duplicates.col3 = t.col3 
    and duplicates.mincolx <> t.colx) 

El problema es que todavía tiene filas en las que las cuatro columnas son los mismos. Para deshacerse de estos, después de ejecutar la primera consulta, debe usar una tabla temporal.

SELECT distinct col1, col2, col3, colx 
INTO temp 
    FROM (SELECT col1, col2, col3 
     from t 
     group by col1, col2, col3 
     having count(1) > 1) subq; 

DELETE from t where exists 
    (select 1 from temp 
    where temp.col1 = t.col1 
     and temp.col2 = t.col2 
     and temp.col3 = t.col3); 

Here's an example SQLFiddle.

0

que asumir que utilizas SQL Server 2005/2008.

SELECT col1, 
     col2, 
     col3, 
     colx 
FROM 
    (SELECT *, 
      row_number() OVER (PARTITION BY col1,col2,col3 
          ORDER BY colx) AS r 
    FROM table_name) a 
WHERE r = 1; 
0

solución más simple podría ser la siguiente supongamos que tenemos mesa emp_dept (empid, deptid) que tiene filas duplicadas, En base de datos Oracle

delete from emp_dept where exists (select * from emp_dept i where i.empid = emp_dept.empid and i.deptid = emp_dept.deptid and i.rowid < emp_dept.rowid) 

En el servidor sql o cualquier base de datos que no sea compatible con la función de identificación de fila, tenemos que agregar una columna de identidad para identificar cada fila. decir que hemos añadido nid como la identidad de la tabla

alter table emp_dept add nid int identity(1,1) -- to add identity column 

ahora consulta para eliminar duplicados podría escribir como

delete from emp_dept where exists (select * from emp_dept i where i.empid = emp_dept.empid and i.deptid = emp_dept.deptid and i.nid< emp_dept.nid) 

Aquí el concepto es eliminar todas las filas para las que existe otras filas que tienen similares valores centrales pero rowid o identidad más pequeños. Por lo tanto, si existen filas duplicadas, se eliminará una que tenga una identificación de fila o identidad más alta. y para la fila no hay duplicado, falla al encontrar la identificación de la fila inferior, por lo que no se borrará.

0

probar este código bt en su propio riesgo

Delete from Table_name 
WHERE Table_name.%%physloc%% 
     NOT IN (SELECT MAX(b.%%physloc%%) 
       FROM Table_name b 
       group by Col_1,Col_2) 

Segundo método usando row_number() Este método seguro es

WITH CTE_Dup AS 
(

SELECT * ROW_NUMBER()OVER (PARTITIONBY SalesOrderno, ItemNo ORDER BY SalesOrderno, ItemNo) 
AS ROW_NO 
from dbo.SalesOrderDetails 
) 
Delete FROM CTE_Dup; 
Cuestiones relacionadas