Запрос
SELECT id_pk, name, color
, RANK() OVER(PARTITION BY name, color ORDER BY name, color, id_pk) dup
,(SELECT MIN(id) FROM T_pk WHERE T_pk.name = X.name) min_id
FROM T_pk X JOIN T_details ON id=id_pk; определяет наличие дубликатов (значение dup > 1) и минимальное значение id в группе одинаковых имен (min_id). Вот результат выполнения этого запроса:
id_pk name color dup min_id1 John blue 1 11 John red 1 13 John red 2 14 Smith blue 1 22 Smith green 1 22 Smith red 1 26 Tom red 1 6 Теперь нам нужно заменить значение id_pk значением min_pk для всех строк, кроме третьей, т.к. эта строка есть дубликат второй строки, о чем говорит значение dup=2. Запрос на обновление можно написать так:
UPDATE T_details
SET id_pk=min_id
FROM T_details T_d JOIN (
SELECT id_pk, name, color
, RANK() OVER(PARTITION BY name, color ORDER BY name, color, id_pk) dup
,(SELECT MIN(id) FROM T_pk WHERE T_pk.name = X.name) min_id
FROM T_pk X JOIN T_details ON id=id_pk
) Y ON Y.id_pk=T_d.id_pk
WHERE dup =1; После обновления таблица T_details примет следующий вид:
id_pk color1 blue1 red2 blue2 green2 red3 red6 red Как видно, осталась одна лишняя дубликатная строка:
3 red Но о ней можно не беспокоиться, так она будет удалена автоматически при каскадном удалении дубликатов из таблицы T_pk:
DELETE
FROM T_pk
WHERE id > (SELECT MIN(id) FROM T_pk X WHERE X.name = T_pk.name); Последний запрос и является вторым этапом процедуры, в результате выполнения которого мы получим:
Таблица T_pkid name 1 John2 Smith6 Tom Таблица T_detailsid_pk color1 blue1 red2 blue2 green2 red6 red Осталось только наложить ограничение, чтобы избежать появления дубликатов в дальнейшем:
ALTER TABLE T_pk
ADD CONSTRAINT unique_name UNIQUE(name); Dzone.com