Necesito DELETE
filas duplicadas para el sid especificado en una MySQL
tabla.
¿Cómo puedo hacer esto con una consulta SQL?
DELETE (DUPLICATED TITLES) FROM table WHERE SID = "1"
Algo así, pero no sé cómo hacerlo.
Necesito DELETE
filas duplicadas para el sid especificado en una MySQL
tabla.
¿Cómo puedo hacer esto con una consulta SQL?
DELETE (DUPLICATED TITLES) FROM table WHERE SID = "1"
Algo así, pero no sé cómo hacerlo.
Respuestas:
esto elimina duplicados en su lugar, sin hacer una nueva tabla
ALTER IGNORE TABLE `table_name` ADD UNIQUE (title, SID)
nota: solo funciona bien si el índice cabe en la memoria
ALTER IGNORE
.
ALTER TABLE foo ENGINE MyISAM
para evitarlo, volví a cambiar el motor.
Supongamos que tiene una tabla employee
, con las siguientes columnas:
employee (first_name, last_name, start_date)
Para eliminar las filas con una first_name
columna duplicada :
delete
from employee using employee,
employee e1
where employee.id > e1.id
and employee.first_name = e1.first_name
employee
contra sí mismo para una coincidencia de índice y una >
verificación en un índice será lenta para tablas grandes. ¿No sería mejor SELECT MAX(ID) FROM t GROUP BY unique
y luego JOIN
a una coincidencia exacta de ID
a MAX(ID)
?
Después de eliminar duplicados para todos los SID-s, no solo uno solo.
Con mesa de temperatura
CREATE TABLE table_temp AS
SELECT * FROM table GROUP BY title, SID;
DROP TABLE table;
RENAME TABLE table_temp TO table;
Como temp_table
está recién creado, no tiene índices. Deberá volver a crearlos después de eliminar los duplicados. Puede verificar qué índices tiene en la tabla conSHOW INDEXES IN table
Sin tabla temporal:
DELETE FROM `table` WHERE id IN (
SELECT all_duplicates.id FROM (
SELECT id FROM `table` WHERE (`title`, `SID`) IN (
SELECT `title`, `SID` FROM `table` GROUP BY `title`, `SID` having count(*) > 1
)
) AS all_duplicates
LEFT JOIN (
SELECT id FROM `table` GROUP BY `title`, `SID` having count(*) > 1
) AS grouped_duplicates
ON all_duplicates.id = grouped_duplicates.id
WHERE grouped_duplicates.id IS NULL
)
SELECT * FROM table GROUP BY title, SID;
Todo depende de qué tan bien sepa lo que está haciendo.
Crea la tabla e inserta algunas filas:
create table penguins(foo int, bar varchar(15), baz datetime);
insert into penguins values(1, 'skipper', now());
insert into penguins values(1, 'skipper', now());
insert into penguins values(3, 'kowalski', now());
insert into penguins values(3, 'kowalski', now());
insert into penguins values(3, 'kowalski', now());
insert into penguins values(4, 'rico', now());
select * from penguins;
+------+----------+---------------------+
| foo | bar | baz |
+------+----------+---------------------+
| 1 | skipper | 2014-08-25 14:21:54 |
| 1 | skipper | 2014-08-25 14:21:59 |
| 3 | kowalski | 2014-08-25 14:22:09 |
| 3 | kowalski | 2014-08-25 14:22:13 |
| 3 | kowalski | 2014-08-25 14:22:15 |
| 4 | rico | 2014-08-25 14:22:22 |
+------+----------+---------------------+
6 rows in set (0.00 sec)
Eliminar los duplicados en su lugar:
delete a
from penguins a
left join(
select max(baz) maxtimestamp, foo, bar
from penguins
group by foo, bar) b
on a.baz = maxtimestamp and
a.foo = b.foo and
a.bar = b.bar
where b.maxtimestamp IS NULL;
Query OK, 3 rows affected (0.01 sec)
select * from penguins;
+------+----------+---------------------+
| foo | bar | baz |
+------+----------+---------------------+
| 1 | skipper | 2014-08-25 14:21:59 |
| 3 | kowalski | 2014-08-25 14:22:15 |
| 4 | rico | 2014-08-25 14:22:22 |
+------+----------+---------------------+
3 rows in set (0.00 sec)
Ya ha terminado, se eliminan las filas duplicadas, se guarda la última por marca de tiempo.
¿No tiene una timestamp
o una columna de índice única para ordenar? Estás viviendo en un estado de degeneración. Tendrá que realizar pasos adicionales para eliminar filas duplicadas.
crea la tabla de pingüinos y agrega algunas filas
create table penguins(foo int, bar varchar(15));
insert into penguins values(1, 'skipper');
insert into penguins values(1, 'skipper');
insert into penguins values(3, 'kowalski');
insert into penguins values(3, 'kowalski');
insert into penguins values(3, 'kowalski');
insert into penguins values(4, 'rico');
select * from penguins;
# +------+----------+
# | foo | bar |
# +------+----------+
# | 1 | skipper |
# | 1 | skipper |
# | 3 | kowalski |
# | 3 | kowalski |
# | 3 | kowalski |
# | 4 | rico |
# +------+----------+
haga un clon de la primera tabla y cópiela.
drop table if exists penguins_copy;
create table penguins_copy as ( SELECT foo, bar FROM penguins );
#add an autoincrementing primary key:
ALTER TABLE penguins_copy ADD moo int AUTO_INCREMENT PRIMARY KEY first;
select * from penguins_copy;
# +-----+------+----------+
# | moo | foo | bar |
# +-----+------+----------+
# | 1 | 1 | skipper |
# | 2 | 1 | skipper |
# | 3 | 3 | kowalski |
# | 4 | 3 | kowalski |
# | 5 | 3 | kowalski |
# | 6 | 4 | rico |
# +-----+------+----------+
El agregado máximo opera sobre el nuevo índice moo:
delete a from penguins_copy a left join(
select max(moo) myindex, foo, bar
from penguins_copy
group by foo, bar) b
on a.moo = b.myindex and
a.foo = b.foo and
a.bar = b.bar
where b.myindex IS NULL;
#drop the extra column on the copied table
alter table penguins_copy drop moo;
select * from penguins_copy;
#drop the first table and put the copy table back:
drop table penguins;
create table penguins select * from penguins_copy;
observar y limpiar
drop table penguins_copy;
select * from penguins;
+------+----------+
| foo | bar |
+------+----------+
| 1 | skipper |
| 3 | kowalski |
| 4 | rico |
+------+----------+
Elapsed: 1458.359 milliseconds
¿Qué está haciendo esa gran declaración de eliminación de SQL?
Los pingüinos de mesa con el alias 'a' se unen en un subconjunto de pingüinos de mesa llamado alias 'b'. La tabla de la derecha 'b', que es un subconjunto, encuentra la marca de tiempo máxima [o max moo] agrupada por columnas foo y bar. Esto coincide con la tabla de la izquierda 'a'. (foo, bar, baz) a la izquierda tiene cada fila en la tabla. El subconjunto de la derecha 'b' tiene un (maxtimestamp, foo, bar) que coincide con el izquierdo solo en el que ES el máximo.
Cada fila que no es ese máximo tiene el valor maxtimestamp de NULL. Filtra hacia abajo en esas filas NULL y tienes un conjunto de todas las filas agrupadas por foo y bar que no es el último baz de marca de tiempo. Eliminar esos.
Haga una copia de seguridad de la tabla antes de ejecutar esto.
Evite que este problema vuelva a ocurrir en esta tabla:
Si conseguiste que esto funcione, y apagó tu fuego de "fila duplicada". Excelente. Ahora defina una nueva clave compuesta única en su tabla (en esas dos columnas) para evitar que se agreguen más duplicados en primer lugar.
Al igual que un buen sistema inmunitario, las filas malas ni siquiera deberían permitirse en la mesa en el momento de la inserción. Más tarde, todos los programas que agreguen duplicados transmitirán su protesta, y cuando los arregles, este problema nunca volverá a aparecer.
ID
columna de incremento automático , entonces la ON
cláusula solo debe coincidir con la ID
columna, nada más.
Después de encontrarme con este problema, en una gran base de datos, no estaba completamente impresionado con el rendimiento de ninguna de las otras respuestas. Quiero mantener solo la última fila duplicada y eliminar el resto.
En una declaración de una consulta, sin una tabla temporal, esto funcionó mejor para mí,
DELETE e.*
FROM employee e
WHERE id IN
(SELECT id
FROM (SELECT MIN(id) as id
FROM employee e2
GROUP BY first_name, last_name
HAVING COUNT(*) > 1) x);
La única advertencia es que tengo que ejecutar la consulta varias veces, pero incluso con eso, encontré que funcionó mejor para mí que las otras opciones.
Esto siempre parece funcionar para mí:
CREATE TABLE NoDupeTable LIKE DupeTable;
INSERT NoDupeTable SELECT * FROM DupeTable group by CommonField1,CommonFieldN;
Que mantiene la ID más baja en cada uno de los duplicados y el resto de los registros no duplicados.
También he hecho lo siguiente para que el problema de engaño ya no ocurra después de la eliminación:
CREATE TABLE NoDupeTable LIKE DupeTable;
Alter table NoDupeTable Add Unique `Unique` (CommonField1,CommonField2);
INSERT IGNORE NoDupeTable SELECT * FROM DupeTable;
En otras palabras, creo un duplicado de la primera tabla, agrego un índice único en los campos de los que no quiero duplicados y luego hago uno Insert IGNORE
que tiene la ventaja de no fallar como lo Insert
haría normalmente la primera vez que intentó agregar un registro duplicado basado en los dos campos e ignora dichos registros.
Al mover fwd se hace imposible crear registros duplicados basados en esos dos campos.
ORDER BY
en el SELECT
para estar seguro de qué registro realmente pasa al NoDupeTable
?
ORDER by ID Asc
, no podría doler, así que editaré mi respuesta de todos modos.
Select Max(ID)
luego, Order by Max(ID)
pero todo lo que haría sería invertir el orden de la inserción. Para obtener la ID más alta requeriría Creo que una selección select más compleja ya que, independientemente de cómo ordene arriba, tomará los valores de campo de la ID más baja.
MAX(ID)
o MIN(ID)
y nombres de columna en lugar de *
en el SELECT FROM DupeTable
de que, de lo contrario vas a tener uno de los ID
's al azar. De hecho, muchos SQL e incluso MySQL estrictos requieren llamar a una función agregada en cada columna no especificada en la GROUP BY
cláusula.
ID,First,Last,Notes
y registros 1,Bob,Smith,NULL
y 2,Bob,Smith,Arrears
luego hacer un SELECT *Max(ID), First,Last,Notes FROM DupeTable group by First,Last
, ambos devolverían el mismo registro, 1, excepto con una ID diferente. Max (ID) volvería 2,Bob,Smith,NULL
y Min (ID) volvería 1,Bob,Smith,NULL
. Para obtener el segundo registro con 'Atrasos' en las notas se requiere una unión, creo.
Aquí hay una respuesta simple:
delete a from target_table a left JOIN (select max(id_field) as id, field_being_repeated
from target_table GROUP BY field_being_repeated) b
on a.field_being_repeated = b.field_being_repeated
and a.id_field = b.id_field
where b.id_field is null;
and a.id_field = b.id
LEFT JOIN
to b
solo necesita comparar b.id
= a.id_field
suponiendo que field_id
es un ID de incremento automático único. entonces a.field_being_repeated = b.field_being_repeated
es extraño. ( b.id_field
tampoco existe en esta consulta es b.id
.
Este trabajo para mí para eliminar registros antiguos:
delete from table where id in
(select min(e.id)
from (select * from table) e
group by column1, column2
having count(*) > 1
);
Puede reemplazar min (e.id) a max (e.id) para eliminar los registros más recientes.
Creo que la solución de Werner anterior es la más conveniente porque funciona independientemente de la presencia de una clave principal, no se mete con las tablas, usa sql a prueba de futuro, es muy comprensible.
Como dije en mi comentario, esa solución no se ha explicado correctamente. Entonces esto es mío, basado en eso.
1) agregar una nueva columna booleana
alter table mytable add tokeep boolean;
2) agregue una restricción en las columnas duplicadas Y la nueva columna
alter table mytable add constraint preventdupe unique (mycol1, mycol2, tokeep);
3) establece la columna booleana en verdadero. Esto tendrá éxito solo en una de las filas duplicadas debido a la nueva restricción
update ignore mytable set tokeep = true;
4) eliminar filas que no se han marcado como mantenimiento
delete from mytable where tokeep is null;
5) suelte la columna agregada
alter table mytable drop tokeep;
Le sugiero que mantenga la restricción que agregó, para evitar nuevos duplicados en el futuro.
Este procedimiento eliminará todos los duplicados (incluidos los múltiplos) en una tabla, manteniendo el último duplicado. Esta es una extensión de Recuperar el último registro en cada grupo
Espero que sea útil para alguien.
DROP TABLE IF EXISTS UniqueIDs;
CREATE Temporary table UniqueIDs (id Int(11));
INSERT INTO UniqueIDs
(SELECT T1.ID FROM Table T1 LEFT JOIN Table T2 ON
(T1.Field1 = T2.Field1 AND T1.Field2 = T2.Field2 #Comparison Fields
AND T1.ID < T2.ID)
WHERE T2.ID IS NULL);
DELETE FROM Table WHERE id NOT IN (SELECT ID FROM UniqueIDs);
Otra forma fácil ... usando ACTUALIZAR IGNORE:
U tiene que usar un índice en una o más columnas (tipo índice). Cree una nueva columna de referencia temporal (que no forme parte del índice). En esta columna, marca los exclusivos actualizándolos con la cláusula ignorar. Paso a paso:
Agregue una columna de referencia temporal para marcar los únicos:
ALTER TABLE `yourtable` ADD `unique` VARCHAR(3) NOT NULL AFTER `lastcolname`;
=> esto agregará una columna a su tabla.
Actualice la tabla, intente marcar todo como único, pero ignore los posibles errores debido a un problema clave duplicado (se omitirán los registros):
UPDATE IGNORE `yourtable` SET `unique` = 'Yes' WHERE 1;
=> encontrará que sus registros duplicados no se marcarán como únicos = 'Sí', en otras palabras, solo uno de cada conjunto de registros duplicados se marcará como único.
Elimina todo lo que no sea único:
DELETE * FROM `yourtable` WHERE `unique` <> 'Yes';
=> Esto eliminará todos los registros duplicados.
Suelta la columna ...
ALTER TABLE `yourtable` DROP `unique`;
unique
columna DEBE agregarse a una restricción única junto con las columnas que están duplicadas actualmente, de lo contrario, todo no funciona porque SET unique
= 'Sí' nunca fallará.
unique
es una palabra clave mysql. Por lo tanto, debe tener los backticks (como ya se muestra correctamente). Usar otra palabra para la columna podría ser más conveniente.
Eliminar duplicados en tablas MySQL es un problema común, que generalmente viene con necesidades específicas. En caso de que alguien esté interesado, aquí ( Eliminar filas duplicadas en MySQL ) explico cómo usar una tabla temporal para eliminar duplicados de MySQL de manera confiable y rápida, también válida para manejar grandes fuentes de datos (con ejemplos para diferentes casos de uso).
Ali , en tu caso, puedes ejecutar algo como esto:
-- create a new temporary table
CREATE TABLE tmp_table1 LIKE table1;
-- add a unique constraint
ALTER TABLE tmp_table1 ADD UNIQUE(sid, title);
-- scan over the table to insert entries
INSERT IGNORE INTO tmp_table1 SELECT * FROM table1 ORDER BY sid;
-- rename tables
RENAME TABLE table1 TO backup_table1, tmp_table1 TO table1;
Me encanta la respuesta de @ eric, pero parece que no funciona si tienes una mesa realmente grande (la obtengo The SELECT would examine more than MAX_JOIN_SIZE rows; check your WHERE and use SET SQL_BIG_SELECTS=1 or SET MAX_JOIN_SIZE=# if the SELECT is okay
cuando intento ejecutarla). Así que limité la consulta de combinación para considerar solo las filas duplicadas y terminé con:
DELETE a FROM penguins a
LEFT JOIN (SELECT COUNT(baz) AS num, MIN(baz) AS keepBaz, foo
FROM penguins
GROUP BY deviceId HAVING num > 1) b
ON a.baz != b.keepBaz
AND a.foo = b.foo
WHERE b.foo IS NOT NULL
La cláusula WHERE en este caso permite que MySQL ignore cualquier fila que no tenga un duplicado y también ignorará si esta es la primera instancia del duplicado, por lo que solo se ignorarán los duplicados posteriores. Cambie MIN(baz)
a MAX(baz)
para mantener la última instancia en lugar de la primera.
Esto funciona para tablas grandes:
CREATE Temporary table duplicates AS select max(id) as id, url from links group by url having count(*) > 1;
DELETE l from links l inner join duplicates ld on ld.id = l.id WHERE ld.id IS NOT NULL;
Para eliminar el cambio más antiguo max(id)
amin(id)
Esto hará que la columna se convierta column_name
en una clave principal y, mientras tanto, ignore todos los errores. Por lo tanto, eliminará las filas con un valor duplicado para column_name
.
ALTER IGNORE TABLE `table_name` ADD PRIMARY KEY (`column_name`);
Creo que esto funcionará básicamente copiando la tabla y vaciándola y luego volviendo a colocar solo los valores distintos, pero revísela antes de hacerlo en grandes cantidades de datos.
Crea una copia al carbón de tu mesa
crear tabla temp_table como oldtablename; inserte temp_table select * from oldtablename;
Vacía tu mesa original
DELETE * de oldtablename;
Copia todos los valores distintos de la tabla copiada a su tabla original
INSERTAR oldtablename SELECT * del grupo temp_table por nombre, apellido, dob
Elimina tu tabla temporal.
Drop Table temp_table
Necesita agrupar por todos los campos que desea mantener distintos.
DELETE T2
FROM table_name T1
JOIN same_table_name T2 ON (T1.title = T2.title AND T1.ID <> T2.ID)
así es como generalmente elimino los duplicados
Puede usar una cláusula DISTINCT para seleccionar la lista "limpiada" (y aquí hay un ejemplo muy sencillo sobre cómo hacerlo).
DISTINCT
usarlo, pierde toda la información sobre duplicados que podría haber tenido en primer lugar. ¿Puedes mostrar una forma de eliminar duplicados usándolo?
¿Podría funcionar si los cuenta y luego agrega un límite a su consulta de eliminación dejando solo uno?
Por ejemplo, si tiene dos o más, escriba su consulta de esta manera:
DELETE FROM table WHERE SID = 1 LIMIT 1;
Solo hay unos pocos pasos básicos al eliminar datos duplicados de su tabla:
Aquí está el tutorial completo: https://blog.teamsql.io/deleting-duplicate-data-3541485b3473