Иногда в базах данных встречаются таблицы без первичного ключа. Это позволяет пользователям вносить в подобные таблицы данные содержащие полные дубликаты строк. Что делать, если перед вами стоит задача почистить эту таблицу от дубликатов?
Создадим тестовую таблицу и заполним ее данными, содержащими дубликаты строк:
PostgresSQL легко позволяет решить эту проблему с помощью скрытых системных столбцов, которые создаются в каждой таблице самой СУБД. Первым и самым очевидным кандидатом является известный всем системный столбец "OID" (Object Identifier):
Метод работает, но имеет недостатки:
1-й - большой. В пользовательские таблицы столбец "OID" добавляется, только если при создании таблицы указывается параметр "WITH OIDS" или включен параметр конфигурации "default_with_oids". Т.е. столбца "OID" в таблице может и не быть!
2-й - небольшой и маловероятный. Столбец "OID" реализован как 32-х битное целое число. В больших или долгоживущих базах данных этот счетчик может пойти по кругу, тем самым существует вероятность, что значение этого столбца в одной таблице может повториться.
Альтернативой столбцу "OID" является другое системное поле - "CTID", которое идентифицирует физическое расположение строки в таблице. Оно присутствует в таблице всегда и гарантированно является уникальным. Возвращаем таблицу "test" в исходное состояние и выполняем запрос:
P.S. При использовании данного способа удаления дубликатов строк в таблице, необходимо учитывать, что на большой таблице, этот запрос потребует очень много ресурсов и может тормознуть сервер.
Создадим тестовую таблицу и заполним ее данными, содержащими дубликаты строк:
В исходном состоянии таблица "test" содержит пять строк, две из которых - лишние:CREATE TABLE test ( id INTEGER, name VARCHAR(100) ); INSERT INTO test(id, name) VALUES (1, 'Вера'); INSERT INTO test(id, name) VALUES (2, 'Надежда'); INSERT INTO test(id, name) VALUES (1, 'Вера'); INSERT INTO test(id, name) VALUES (3, 'Любовь'); INSERT INTO test(id, name) VALUES (1, 'Вера');
id | name |
1 | Вера |
2 | Надежда |
1 | Вера |
3 | Любовь |
1 | Вера |
PostgresSQL легко позволяет решить эту проблему с помощью скрытых системных столбцов, которые создаются в каждой таблице самой СУБД. Первым и самым очевидным кандидатом является известный всем системный столбец "OID" (Object Identifier):
В результате выполнения этого запроса все дубликаты из таблицы исчезли, и в таблице мы видим только уникальные строки:DELETE FROM test WHERE oid NOT IN (SELECT MIN(oid) FROM test GROUP BY test.*);
id | name |
1 | Вера |
2 | Надежда |
3 | Любовь |
Метод работает, но имеет недостатки:
1-й - большой. В пользовательские таблицы столбец "OID" добавляется, только если при создании таблицы указывается параметр "WITH OIDS" или включен параметр конфигурации "default_with_oids". Т.е. столбца "OID" в таблице может и не быть!
2-й - небольшой и маловероятный. Столбец "OID" реализован как 32-х битное целое число. В больших или долгоживущих базах данных этот счетчик может пойти по кругу, тем самым существует вероятность, что значение этого столбца в одной таблице может повториться.
Альтернативой столбцу "OID" является другое системное поле - "CTID", которое идентифицирует физическое расположение строки в таблице. Оно присутствует в таблице всегда и гарантированно является уникальным. Возвращаем таблицу "test" в исходное состояние и выполняем запрос:
В результате выполнения этого запроса в таблице "test" остались только три уникальные строки.DELETE FROM test WHERE ctid NOT IN (SELECT MIN(ctid) FROM test GROUP BY test.*);
P.S. При использовании данного способа удаления дубликатов строк в таблице, необходимо учитывать, что на большой таблице, этот запрос потребует очень много ресурсов и может тормознуть сервер.
А если на уникальность надо проверить не все поля, а только часть?
ОтветитьУдалитьПопробуйте так:
УдалитьDELETE FROM test
WHERE ctid NOT IN (SELECT MIN(ctid)
FROM test
GROUP BY field1, field2, field10);