Удалить дубликаты записей из таблицы Postgresql без первичного ключа?
У меня есть таблица типа
CREATE TABLE meta.fk_payment1
(
id serial NOT NULL,
settlement_ref_no character varying,
order_type character varying,
fulfilment_type character varying,
seller_sku character varying,
wsn character varying,
order_id character varying,
order_item_id bigint,
....
);
Я вставляю данные из файла csv, где все столбцы одинаковы, а не
id column
В случае, если файл csv загружен более одного раза, данные будут дублироваться.
но id не будет, а id будет первичным.
поэтому я хочу удалить всю повторяющуюся строку без использования первичного ключа.
Мне нужно сделать это на отдельной таблице
Ответы
Ответ 1
Скопируйте отдельные данные в рабочую таблицу fk_payment1_copy
. Самый простой способ сделать это - использовать into
SELECT max(id),settlement_ref_no ...
INTO fk_payment1_copy
from fk_payment1
GROUP BY settlement_ref_no ...
удалить все строки из fk_payment1
delete from fk_payment1
и скопируйте данные из таблицы fk_payment1_copy
в fk_payment1
insert into fk_payment1
select id,settlement_ref_no ...
from fk_payment1_copy
Ответ 2
Вы можете сделать это
например.
DELETE FROM table_name
WHERE ctid NOT IN
(SELECT MAX(dt.ctid)
FROM table_name As dt
GROUP BY dt.*);
запустите этот запрос
DELETE FROM meta.fk_payment1
WHERE ctid NOT IN
(SELECT MAX(dt.ctid)
FROM meta.fk_payment1 As dt
GROUP BY dt.*);
Ответ 3
Немного не уверен в части первичного ключа в вопросе, но в любом случае id
не обязательно должен быть первичным ключом, он просто должен быть уникальным. Как и должно быть, так как он серийный. Поэтому, если он имеет уникальные значения, вы можете сделать это следующим образом:
DELETE FROM fk_payment1 f WHERE EXISTS
(SELECT * FROM fk_payment1 WHERE id<f.id
AND settlement_ref_no=f.settlement_ref_no
AND ...)
Просто нужно добавить все столбцы в запрос выбора. Таким образом будут удалены все строки с одинаковыми значениями (кроме id) и после этой строки (отсортированные по id).
(Именование таблицы с префиксом fk_ делает ее похожим на внешний ключ.)
Ответ 4
если таблица не очень велика, вы можете сделать:
-- create temporary table and select distinct into it.
CREATE TEMP TABLE tmp_table AS
SELECT DISTINCT column_1, column_2
FROM original_table ORDER BY column_1, column_2;
-- clear the original table
TRUNCATE original_table;
-- copy data back in again
INSERT INTO original_table(column_1, column_2)
SELECT * FROM tmp_table ORDER BY column_1, column_2;
-- clean up
DROP TABLE tmp_table
- для больших таблиц удалите команду
TEMP
из создания tmp_table
- Это решение пригодится при работе с JPA (Hibernate), созданным
@ElementCollection
, которые создаются без первичного ключа.
Ответ 5
Таким образом, в PG wiki есть пятно. https://wiki.postgresql.org/wiki/Deleting_duplicates
Этот запрос делает это для всех строк tablename, имеющих одинаковые столбцы1, column2 и column3.
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);
Я тестировал это при снятии дуплексных 600k строк, что привело к 200k уникальным строкам. Решение с использованием group by и NOT IN заняло 3h +, это занимает примерно 3 секунды.