Удалить повторяющиеся записи в PostgreSQL - PullRequest
86 голосов
/ 05 июля 2011

У меня есть таблица в базе данных PostgreSQL 8.3.8, в которой нет ключей / ограничений и несколько строк с одинаковыми значениями.

Я хотел бы удалить все дубликаты и сохранить только1 копия каждой строки.

В частности, существует один столбец (называемый «ключом»), который можно использовать для идентификации дубликатов (т. Е. Для каждого отдельного «ключа» должна существовать только одна запись).

Как я могу это сделать?(в идеале с помощью одной команды SQL) Скорость в этом случае не является проблемой (всего несколько строк).

Ответы [ 8 ]

136 голосов
/ 19 октября 2012

Более быстрое решение -

DELETE FROM dups a USING (
      SELECT MIN(ctid) as ctid, key
        FROM dups 
        GROUP BY key HAVING COUNT(*) > 1
      ) b
      WHERE a.key = b.key 
      AND a.ctid <> b.ctid
61 голосов
/ 05 июля 2011
DELETE FROM dupes a
WHERE a.ctid <> (SELECT min(b.ctid)
                 FROM   dupes b
                 WHERE  a.key = b.key);
44 голосов
/ 16 октября 2017

Это быстро и лаконично:

DELETE FROM dupes T1
    USING   dupes T2
WHERE   T1.ctid < T2.ctid  -- delete the older versions
    AND T1.key  = T2.key;  -- add more columns if needed

См. Также мой ответ на Как удалить повторяющиеся строки без уникального идентификатора , который включает в себя дополнительную информацию.

13 голосов
/ 16 ноября 2016

Я пробовал это:

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);

предоставлено Postgres wiki:

https://wiki.postgresql.org/wiki/Deleting_duplicates

6 голосов
/ 06 октября 2016

Я должен был создать свою собственную версию. Версия, написанная @a_horse_with_no_name, слишком медленная для моей таблицы (21 млн строк). А @rapimo просто не удаляет дуплики.

Вот что я использую на PostgreSQL 9.5

DELETE FROM your_table
WHERE ctid IN (
  SELECT unnest(array_remove(all_ctids, actid))
  FROM (
         SELECT
           min(b.ctid)     AS actid,
           array_agg(ctid) AS all_ctids
         FROM your_table b
         GROUP BY key1, key2, key3, key4
         HAVING count(*) > 1) c);
5 голосов
/ 05 июля 2011

Я бы использовал временную таблицу:

create table tab_temp as
select distinct f1, f2, f3, fn
  from tab;

Затем удалите tab и переименуйте tab_temp в tab.

0 голосов
/ 10 августа 2017

РАБОТАЕТ ДЛЯ ВСЕХ ВАРИАНТОВ / ЦВЕТОВ SQL (ТАКЖЕ РАБОТАЕТ В AWS REDSHIFT [POSTGRESQL])

1. Лучший метод удаления дубликатов -> с использованием CTE

WITH DUPLICATE_CTE AS 
( SELECT KEY,COUNT(1) AS RANKED FROM <SCHEMANAME>.<TABLENAME>
  GROUP BY KEY )
DELETE FROM DUPLICATE_CTE WHERE RANKED > 1

2. Простой метод -> Использование row_number () / rank, dens_rank () Функция

DELETE FROM <TABLE_ALIAS>
FROM (
SELECT <COLUMN_NAMES>,
ROW_NUMBER() OVER (PARTITION BY KEY) AS RANKED
FROM <SCHEMANAME>.<TABLENAME>
) <TABLE_ALIAS>
WHERE <TABLE_ALIAS>.RANKED >1

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

3.Миряне (он же LAME: p) Метод (самый общий метод для удаления совершенных дубликатов)

DROP TABLE IF EXISTS backupOfTheTableContainingDuplicates;

CREATE TABLE aNewEmptyTemporaryOrBackupTable 
AS SELECT DISTINCT * FROM originalTableContainingDuplicates;

TRUNCATE TABLE originalTableContainingDuplicates;

INSERT INTO originalTableContainingDuplicates SELECT * FROM 
aNewEmptyTemporaryOrBackupTable ;

DROP TABLE aNewEmptyTemporaryOrBackupTable ;

ОБЪЯСНЕНИЕ ВЫШЕГО СКРИПТА SQL

Итак,

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

2-й запрос создает новую таблицу (временная / резервная) суникальные записи в исходной таблице, содержащие дубликаты, поэтому новая временная таблица совпадает с исходной таблицей МИНУС дублирующих записей.

3-й запрос усекает или очищает исходную таблицу.

4-йЗапрос, вставка или копирование всех уникальныхво временную таблицу переходит к исходной таблице, которая была недавно усечена (поэтому не имеет данных).После выполнения этого запроса исходная таблица будет заполнена уникальными данными, которые были во временной таблице.

5-й запрос удаляет / удаляет ненужную временную таблицу.

Таким образом, конечный результат равенисходная таблица содержит только УНИКАЛЬНЫЕ ЗАПИСИ и не содержит дубликатов.

0 голосов
/ 27 ноября 2016

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

        CREATE TEMP TABLE dupids AS
        select id from (
                    select value, id, row_number() 
over (partition by value order by value) 
    as rownum from terms
                  ) tmp
                  where rownum >= 2;

delete from [table] where id in (select id from dupids)
...