Как удалить одну из двух совершенно одинаковых строк?

я чищу таблицу без первичного ключа (я знаю, я знаю, о чем они думали?). Я не могу добавить первичный ключ, потому что в столбце есть дубликат, который станет ключом. Повторяющееся значение происходит из одной из двух строк, которые во всех отношениях идентичны. Я не могу удалить строку через GUI (в этом случае MySQL Workbench, но я ищу агностический подход к базе данных), потому что он отказывается выполнять задачи на таблицах без первичных ключей (или, по крайней мере, UQ NN столбец), и я не могу добавить первичный ключ, потому что в столбце есть дубликат, который станет ключом. Значение duplicate происходит от единицы...

Как я могу удалить одного из близнецов?

13 ответов


один из вариантов решения вашей проблемы-создать новую таблицу с той же схемой, а затем сделать:

INSERT INTO new_table (SELECT DISTINCT * FROM old_table)

а затем просто переименуйте таблицы.

вам, конечно, потребуется примерно столько же места, сколько ваш стол требует свободного места на диске, чтобы сделать это!

Это не эффективно, но это невероятно прост.


SET ROWCOUNT 1
DELETE FROM [table] WHERE ....
SET ROWCOUNT 0

это удалит только одну из двух одинаковых строк


обратите внимание, что MySQL имеет собственное расширение DELETE, которая составляет DELETE ... LIMIT, который работает обычным способом, который вы ожидаете от LIMIT: http://dev.mysql.com/doc/refman/5.0/en/delete.html

опция ограничения row_count для MySQL для удаления сообщает серверу максимальное число строк, которые необходимо удалить перед возвратом элемента управления клиент. Это можно использовать для обеспечения того, чтобы данный оператор DELETE не занимает слишком много времени. Вы можете просто повторить удаление оператор до тех пор, пока количество затронутых строк не будет меньше предела значение.

таким образом, вы можете использовать DELETE FROM some_table WHERE x="y" AND foo="bar" LIMIT 1; обратите внимание, что нет простого способа сказать "удалить все, кроме одного" - просто продолжайте проверять, есть ли у вас дубликаты строк.


для PostgreSQL вы можете сделать следующее:

DELETE FROM tablename
WHERE id IN (SELECT id
          FROM (SELECT id, ROW_NUMBER() 
               OVER (partition BY column1, column2, column3 ORDER BY id) AS rnum
               FROM tablename) t
          WHERE t.rnum > 1);

column1, column2, column3 будет набор столбцов, которые имеют повторяющиеся значения.

ссылка здесь.


Это может быть выполнено с помощью CTE и ROW_NUMBER() функции, как показано ниже:

/* Sample Data */
    CREATE TABLE #dupes (ID INT, DWCreated DATETIME2(3))

    INSERT INTO #dupes (ID, DWCreated) SELECT 1, '2015-08-03 01:02:03.456'
    INSERT INTO #dupes (ID, DWCreated) SELECT 2, '2014-08-03 01:02:03.456'
    INSERT INTO #dupes (ID, DWCreated) SELECT 1, '2013-08-03 01:02:03.456'

/* Check sample data - returns three rows, with two rows for ID#1 */
    SELECT * FROM #dupes 

/* CTE to give each row that shares an ID a unique number */
    ;WITH toDelete AS
      (
        SELECT ID, ROW_NUMBER() OVER (PARTITION BY ID ORDER BY DWCreated) AS RN
        FROM #dupes 
      )

  /* Delete any row that is not the first instance of an ID */
    DELETE FROM toDelete WHERE RN > 1

/* Check the results: ID is now unique */
    SELECT * FROM #dupes

/* Clean up */
    DROP TABLE #dupes

наличие столбца для заказа удобно, но не обязательно, если у вас нет предпочтения для какой из строк удалить. Это также будет обрабатывать все экземпляры повторяющихся записей, а не заставлять вас удалять одну строку за раз.


delete top (1) работает на Microsoft SQL Server (T-SQL).


пробовал предел 1? Это удалит только 1 из строк, которые соответствуют вашему DELETE запрос

DELETE FROM `table_name` WHERE `column_name`='value' LIMIT 1;

в моем случае я может получите GUI, чтобы дать мне строку значений рассматриваемой строки (в качестве альтернативы, я мог бы сделать это вручную). По предложению коллеги, в чьем долгу я остаюсь, я использовал это для создания инструкции INSERT:

INSERT
'ID1219243408800307444663', '2004-01-20 10:20:55', 'INFORMATION', 'admin' (...)
INTO some_table;

Я проверил оператор insert, так что теперь у меня были тройняшки. Наконец, я запустил простое удаление, чтобы удалить все из них...

DELETE FROM some_table WHERE logid = 'ID1219243408800307444663';

с последующей вставкой еще раз, оставив меня с одной строкой, и яркие возможности первичного ключа.


в случае, если вы можете добавить столбец типа

  ALTER TABLE yourtable ADD IDCOLUMN bigint NOT NULL IDENTITY (1, 1)

сделать это.

затем подсчитайте группировку строк по столбцу проблемы, где count >1, это идентифицирует ваших близнецов (или тройняшек или что-то еще).

затем выберите столбец проблемы, где его содержимое равно идентифицированному содержимому выше, и проверьте идентификаторы в IDCOLUMN.

удалить из таблицы, где IDCOLUMN равен одному из этих идентификаторов.


вы можете использовать max, что было актуально в моем случае.

DELETE FROM [table] where id in 
(select max(id) from [table] group by id, col2, col3 having count(id) > 1)

Не забудьте сначала проверить свои результаты и иметь ограничивающее условие в вашем "имеющем" clausule. С таким огромным запросом удаления вы можете сначала обновить свою базу данных.


это работает для PostgreSQL

DELETE FROM tablename WHERE id = 123 AND ctid IN (SELECT ctid FROM tablename WHERE id = 123 LIMIT 1)

Я добавил столбец Guid в таблицу и установил его для создания нового идентификатора для каждой строки. Затем я мог бы удалить строки с помощью GUI.


на PostgreSQL существует неявный столбец с именем ctid. Вижу wiki. Таким образом, вы можете использовать следующее:

WITH cte1 as(
    SELECT unique_column, max( ctid ) as max_ctid
    FROM table_1
    GROUP BY unique_column
    HAVING count(*) > 1
), cte2 as(
    SELECT t.ctid as target_ctid
    FROM table_1 t
    JOIN cte1 USING( unique_column )
    WHERE t.ctid != max_ctid
)
DELETE FROM table_1
WHERE ctid IN( SELECT target_ctid FROM cte2 )

Я не уверен, насколько безопасно использовать это, когда есть возможность одновременных обновлений. Таким образом, можно найти разумным сделать LOCK TABLE table_1 IN ACCESS EXCLUSIVE MODE; перед тем, как очистка.