Мне нужно DELETE
дублировать строки для указанного SID наMySQL
таблице.
Как я могу сделать это с запросом SQL?
DELETE (DUPLICATED TITLES) FROM table WHERE SID = "1"
Как то так, но я не знаю как это сделать.
Мне нужно DELETE
дублировать строки для указанного SID наMySQL
таблице.
Как я могу сделать это с запросом SQL?
DELETE (DUPLICATED TITLES) FROM table WHERE SID = "1"
Как то так, но я не знаю как это сделать.
Ответы:
это удаляет дубликаты на месте, не создавая новую таблицу
ALTER IGNORE TABLE `table_name` ADD UNIQUE (title, SID)
примечание: хорошо работает, только если индекс помещается в память
ALTER IGNORE
.
ALTER TABLE foo ENGINE MyISAM
обойти это, поменял двигатель обратно после.
Предположим, у вас есть таблица employee
со следующими столбцами:
employee (first_name, last_name, start_date)
Чтобы удалить строки с дублирующимся first_name
столбцом:
delete
from employee using employee,
employee e1
where employee.id > e1.id
and employee.first_name = e1.first_name
employee
против себя для одного совпадения индекса и одна >
проверка индекса будет медленным для больших таблиц. Разве не было бы лучше, SELECT MAX(ID) FROM t GROUP BY unique
а затем JOIN
точное совпадение ID
с MAX(ID)
?
После удаления дубликатов для всех SID-ов, а не только одного.
С временной таблицей
CREATE TABLE table_temp AS
SELECT * FROM table GROUP BY title, SID;
DROP TABLE table;
RENAME TABLE table_temp TO table;
Поскольку temp_table
он только что создан, он не имеет индексов. Вам нужно будет воссоздать их после удаления дубликатов. Вы можете проверить, какие индексы у вас есть в таблице сSHOW INDEXES IN table
Без временной таблицы:
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;
Все зависит от того, насколько хорошо вы знаете, что делаете.
Создайте таблицу и вставьте несколько строк:
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)
Удалить дубликаты на месте:
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)
Все готово, повторяющиеся строки удаляются, последняя отметка времени сохраняется.
У вас нет timestamp
или уникальный индексный столбец для сортировки? Вы живете в состоянии вырождения. Вам придется сделать дополнительные шаги, чтобы удалить дубликаты строк.
создать таблицу пингвинов и добавить несколько строк
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 |
# +------+----------+
сделать клон первой таблицы и скопировать в нее.
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 |
# +-----+------+----------+
Максимальный агрегат работает с новым индексом 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;
наблюдать и убирать
drop table penguins_copy;
select * from penguins;
+------+----------+
| foo | bar |
+------+----------+
| 1 | skipper |
| 3 | kowalski |
| 4 | rico |
+------+----------+
Elapsed: 1458.359 milliseconds
Что делает этот большой оператор удаления SQL?
Настольные пингвины с псевдонимом «a» оставляются соединенными с подмножеством настольных пингвинов, которое называется «b». Правая таблица 'b', которая является подмножеством, находит метку максимального времени [или max moo], сгруппированную по столбцам foo и bar. Это соответствует левой таблице «а». (foo, bar, baz) слева имеет каждую строку в таблице. Правое подмножество 'b' имеет (maxtimestamp, foo, bar), которое соответствует левому только тому, которое является макс.
Каждая строка, отличная от max, имеет значение maxtimestamp, равное NULL. Отфильтруйте эти NULL-строки, и у вас будет набор всех строк, сгруппированных по foo и bar, который не является последней базой меток времени. Удалить те.
Сделайте резервную копию таблицы, прежде чем запускать это.
Предотвратите повторение этой проблемы за этим столом:
Если вы заставили это сработать, и это потушило ваш «двойной ряд» огня. Отлично. Теперь определите новый составной уникальный ключ в вашей таблице (в этих двух столбцах), чтобы предотвратить добавление новых дубликатов.
Как и в случае с хорошей иммунной системой, плохие строки не должны быть допущены к таблице во время вставки. Позже все эти программы, добавляющие дубликаты, будут транслировать свои протесты, и когда вы их исправите, эта проблема больше никогда не возникнет.
ID
столбец с автоинкрементом, то это ON
предложение должно соответствовать только ID
столбцу, и ничего больше.
После того, как я сам столкнулся с этой проблемой в огромной базе данных, я не был полностью впечатлен производительностью других ответов. Я хочу сохранить только последнюю двойную строку и удалить остальные.
В операторе с одним запросом, без временной таблицы, это работало лучше всего для меня,
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);
Единственное предостережение в том, что я должен выполнить запрос несколько раз, но даже при этом я обнаружил, что он работает лучше для меня, чем другие варианты.
Кажется, это всегда работает для меня:
CREATE TABLE NoDupeTable LIKE DupeTable;
INSERT NoDupeTable SELECT * FROM DupeTable group by CommonField1,CommonFieldN;
Который сохраняет наименьший идентификатор для каждого из дупсов и остальных записей не дуплей.
Я также предпринял следующие действия, чтобы проблема удаления больше не возникала после удаления:
CREATE TABLE NoDupeTable LIKE DupeTable;
Alter table NoDupeTable Add Unique `Unique` (CommonField1,CommonField2);
INSERT IGNORE NoDupeTable SELECT * FROM DupeTable;
Другими словами, я создаю дубликат первой таблицы, добавляю уникальный индекс к полям, дубликаты которых я не хочу, и затем делаю тот, Insert IGNORE
который имеет преимущество, заключающееся в том, что он не дает ошибок как обычноInsert
, при первой попытке добавления дубликат записи, основанный на двух полях, и скорее игнорирует любые такие записи.
Перемещение fwd становится невозможным для создания дубликатов записей на основе этих двух полей.
ORDER BY
в, SELECT
чтобы быть уверенным, какая запись на самом деле переходит на NoDupeTable
?
ORDER by ID Asc
не повредит, поэтому я все же отредактирую свой ответ.
Select Max(ID)
а затем, Order by Max(ID)
но все, что нужно сделать, это изменить порядок вставки. Для получения самого высокого идентификатора потребуется, по-моему, более сложное соединение выбора, поскольку независимо от того, как вы заказываете выше, вы будете получать значения полей из более низкого идентификатора.
MAX(ID)
или MIN(ID)
и имена столбцов, а не *
в SELECT FROM DupeTable
хотя, в противном случае вы просто получите один из ID
случайных. Фактически, многие SQL и даже строгие требования MySQL требуют вызова статистической функции для каждого столбца, не указанного в GROUP BY
предложении.
ID,First,Last,Notes
и записями, 1,Bob,Smith,NULL
а 2,Bob,Smith,Arrears
затем выполнение a SELECT *Max(ID), First,Last,Notes FROM DupeTable group by First,Last
вернуло бы одну и ту же запись, 1, за исключением другого идентификатора. Max (ID) вернется, 2,Bob,Smith,NULL
а Min (ID) вернется 1,Bob,Smith,NULL
. Я считаю, что для получения второй записи с "Задолженностью" в примечаниях требуется объединение.
Вот простой ответ:
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
К b
только нужно сравнить b.id
= a.id_field
предполагая field_id
уникальную автоматическое приращение ID. так a.field_being_repeated = b.field_being_repeated
посторонний. (также b.id_field
не существует в этом запросе это b.id
.
Эта работа для меня, чтобы удалить старые записи:
delete from table where id in
(select min(e.id)
from (select * from table) e
group by column1, column2
having count(*) > 1
);
Вы можете заменить min (e.id) на max (e.id), чтобы удалить новейшие записи.
delete p from
product p
inner join (
select max(id) as id, url from product
group by url
having count(*) > 1
) unik on unik.url = p.url and unik.id != p.id;
Я нахожу решение Вернера выше наиболее удобным, поскольку оно работает независимо от наличия первичного ключа, не связывается с таблицами, использует простой SQL-файл, ориентированный на будущее, очень понятно.
Как я сказал в своем комментарии, это решение не было должным образом объяснено все же. Так что это мое, основываясь на этом.
1) добавить новый логический столбец
alter table mytable add tokeep boolean;
2) добавить ограничение на дублированные столбцы и новый столбец
alter table mytable add constraint preventdupe unique (mycol1, mycol2, tokeep);
3) установите для логического столбца значение true. Это будет успешным только в одной из дублированных строк из-за нового ограничения
update ignore mytable set tokeep = true;
4) удалить строки, которые не были помечены как tokeep
delete from mytable where tokeep is null;
5) опустить добавленный столбец
alter table mytable drop tokeep;
Я предлагаю, чтобы вы сохранили ограничение, которое вы добавили, чтобы новые дубликаты были предотвращены в будущем.
Эта процедура удалит все дубликаты (включая кратные) в таблице, сохраняя последний дубликат. Это расширение получения последней записи в каждой группе.
Надеюсь, это кому-нибудь пригодится.
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);
Еще один простой способ ... с помощью UPDATE IGNORE:
Вы должны использовать индекс для одного или нескольких столбцов (тип индекса). Создайте новый столбец временных ссылок (не является частью индекса). В этом столбце вы отмечаете уникальность, обновляя его с помощью условия игнорирования. Шаг за шагом:
Добавьте временный справочный столбец, чтобы отметить уникальность:
ALTER TABLE `yourtable` ADD `unique` VARCHAR(3) NOT NULL AFTER `lastcolname`;
=> это добавит столбец к вашей таблице.
Обновите таблицу, попробуйте пометить все как уникальные, но игнорируйте возможные ошибки из-за дублирования ключа (записи будут пропущены):
UPDATE IGNORE `yourtable` SET `unique` = 'Yes' WHERE 1;
=> вы обнаружите, что ваши повторяющиеся записи не будут помечены как уникальные = 'Да', другими словами, только одна из каждого набора повторяющихся записей будет помечена как уникальная.
Удалите все, что не уникально:
DELETE * FROM `yourtable` WHERE `unique` <> 'Yes';
=> Это удалит все дубликаты записей.
Оставьте столбец ...
ALTER TABLE `yourtable` DROP `unique`;
unique
столбец ДОЛЖЕН быть добавлен к уникальному ограничению вместе со столбцами, которые в настоящее время дублируются, иначе все это не будет работать, потому что SET unique
= 'Yes' никогда не завершится ошибкой.
unique
в виду, что это ключевое слово mysql. Таким образом, он должен иметь галочки (как уже правильно отображается). Использование другого слова для столбца может быть более удобным.
Удаление дубликатов в таблицах MySQL является распространенной проблемой, которая обычно связана с конкретными потребностями. В случае, если кто-то заинтересован, здесь ( Удалите повторяющиеся строки в MySQL ) я объясняю, как использовать временную таблицу для надежного и быстрого удаления дубликатов MySQL, также пригодных для обработки больших источников данных (с примерами для разных вариантов использования).
Али , в вашем случае вы можете запустить что-то вроде этого:
-- 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;
Ответ Love @ eric, но, кажется, он не работает, если у вас действительно большой стол (я получаю, 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
когда пытаюсь его запустить). Поэтому я ограничил запрос на соединение только рассмотрением дублирующихся строк и в итоге получил:
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
Предложение WHERE в этом случае позволяет MySQL игнорировать любую строку, у которой нет дубликата, а также игнорирует, если это первый экземпляр дубликата, поэтому будут игнорироваться только последующие дубликаты. Перейдите MIN(baz)
на MAX(baz)
сохранение последнего экземпляра вместо первого.
Это работает для больших таблиц:
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;
Удалить самое старое изменение max(id)
наmin(id)
Это здесь сделает столбец column_name
первичным ключом, а тем временем проигнорирует все ошибки. Таким образом, будут удалены строки с повторяющимся значением для column_name
.
ALTER IGNORE TABLE `table_name` ADD PRIMARY KEY (`column_name`);
Я думаю, что это сработает, в основном скопировав таблицу и очистив ее, а затем вставив в нее только отдельные значения, но, пожалуйста, дважды проверьте ее, прежде чем делать это для больших объемов данных.
Создает точную копию вашего стола
создать таблицу temp_table как oldtablename; вставить temp_table select * from oldtablename;
Опорожняет ваш оригинальный стол
УДАЛИТЬ * от oldtablename;
Копирует все отдельные значения из скопированной таблицы обратно в исходную таблицу
ВСТАВИТЬ oldtablename SELECT * из группы temp_table по имени, фамилии, dob
Удаляет вашу временную таблицу.
Удалить таблицу temp_table
Вам нужно сгруппировать по всем полям, которые вы хотите сохранить отдельно.
DELETE T2
FROM table_name T1
JOIN same_table_name T2 ON (T1.title = T2.title AND T1.ID <> T2.ID)
вот как я обычно устраняю дубликаты
Вы можете просто использовать предложение DISTINCT, чтобы выбрать «очищенный» список (и вот очень простой пример того, как это сделать).
DISTINCT
вас, вы потеряете любую информацию о дубликатах, которые у вас могли быть. Можете ли вы показать способ удаления дубликатов, используя его?
Может ли это сработать, если вы посчитаете их, а затем добавите ограничение к вашему запросу на удаление, оставив только один?
Например, если у вас есть два или более, напишите ваш запрос следующим образом:
DELETE FROM table WHERE SID = 1 LIMIT 1;
Существует всего несколько основных шагов при удалении дублирующихся данных из вашей таблицы:
Вот полный учебник: https://blog.teamsql.io/deleting-duplicate-data-3541485b3473