Compare commits

..

No commits in common. "7d39aebbd43ef8fb5a960a8edacfe3b89d8798d0" and "8d1a13ee5eae69203153afbcdc0de3553d031f23" have entirely different histories.

View file

@ -23,7 +23,7 @@
-- house_imv_evaluations (house_id) — CASCADE — UNIQUE(house_id) → dedup -- house_imv_evaluations (house_id) — CASCADE — UNIQUE(house_id) → dedup
-- house_suggestions (house_id) — CASCADE — UNIQUE(house_id, ext_item_id) → dedup -- house_suggestions (house_id) — CASCADE — UNIQUE(house_id, ext_item_id) → dedup
-- external_valuations (house_id) — CASCADE — нет ограничивающего UNIQUE -- external_valuations (house_id) — CASCADE — нет ограничивающего UNIQUE
-- address_mismatch_audit (house_id) — CASCADE — UNIQUE(house_id,audit_batch) → dedup -- address_mismatch_audit (house_id) — CASCADE — нет ограничивающего UNIQUE
-- --
-- Идемпотентность: все UPDATE/DELETE ищут по mapping временной таблицы. При повторном -- Идемпотентность: все UPDATE/DELETE ищут по mapping временной таблицы. При повторном
-- запуске mapping будет пустым (дублей нет) → все UPDATE/DELETE затронут 0 строк → no-op. -- запуске mapping будет пустым (дублей нет) → все UPDATE/DELETE затронут 0 строк → no-op.
@ -80,7 +80,7 @@ clusters_with_count AS (
), ),
-- Только дома, входящие в кластер-дубль -- Только дома, входящие в кластер-дубль
dup_houses AS ( dup_houses AS (
SELECT h.id, cl.cluster_key SELECT h.id, c.cluster_key
FROM houses h FROM houses h
JOIN clustered cl ON cl.id = h.id JOIN clustered cl ON cl.id = h.id
JOIN clusters_with_count cw ON cw.cluster_key = cl.cluster_key JOIN clusters_with_count cw ON cw.cluster_key = cl.cluster_key
@ -203,58 +203,47 @@ FROM _108_dup_mapping m
WHERE haa.house_id = m.dup_id; WHERE haa.house_id = m.dup_id;
-- 3c. houses_price_dynamics UNIQUE(house_id, month_date, source) -- 3c. houses_price_dynamics UNIQUE(house_id, month_date, source)
-- Collision-safe: дедуп по ЦЕЛЕВОМУ ключу (canonical, month_date, source) — -- Удалить строки дубля, у которых (month_date,source) уже есть у canonical.
-- ловит и dup-vs-canonical, и dup-vs-dup в кластерах >2. Выживает строка DELETE FROM houses_price_dynamics hpd
-- canonical'а (m.canonical_id IS NULL), иначе минимальный id. USING _108_dup_mapping m
DELETE FROM houses_price_dynamics t WHERE hpd.house_id = m.dup_id
USING ( AND EXISTS (
SELECT t2.id, SELECT 1 FROM houses_price_dynamics hpd2
ROW_NUMBER() OVER ( WHERE hpd2.house_id = m.canonical_id
PARTITION BY COALESCE(m.canonical_id, t2.house_id), t2.month_date, t2.source AND hpd2.month_date = hpd.month_date
ORDER BY (m.canonical_id IS NULL) DESC, t2.id ASC AND hpd2.source = hpd.source
) AS rn );
FROM houses_price_dynamics t2 -- Репойнтить оставшиеся
LEFT JOIN _108_dup_mapping m ON m.dup_id = t2.house_id
) d
WHERE t.id = d.id AND d.rn > 1;
-- Репойнтить оставшиеся (целевой ключ теперь свободен)
UPDATE houses_price_dynamics hpd UPDATE houses_price_dynamics hpd
SET house_id = m.canonical_id SET house_id = m.canonical_id
FROM _108_dup_mapping m FROM _108_dup_mapping m
WHERE hpd.house_id = m.dup_id; WHERE hpd.house_id = m.dup_id;
-- 3d. house_imv_evaluations UNIQUE(house_id) -- 3d. house_imv_evaluations UNIQUE(house_id) — у canonical уже может быть запись
-- Collision-safe: одна evaluation на canonical. Выживает canonical'а, иначе min id. -- Удалить строки дубля если canonical уже имеет evaluation.
DELETE FROM house_imv_evaluations t DELETE FROM house_imv_evaluations hie
USING ( USING _108_dup_mapping m
SELECT t2.id, WHERE hie.house_id = m.dup_id
ROW_NUMBER() OVER ( AND EXISTS (
PARTITION BY COALESCE(m.canonical_id, t2.house_id) SELECT 1 FROM house_imv_evaluations hie2
ORDER BY (m.canonical_id IS NULL) DESC, t2.id ASC WHERE hie2.house_id = m.canonical_id
) AS rn );
FROM house_imv_evaluations t2 -- Репойнтить оставшиеся (canonical не имеет evaluation — забираем от дубля)
LEFT JOIN _108_dup_mapping m ON m.dup_id = t2.house_id
) d
WHERE t.id = d.id AND d.rn > 1;
-- Репойнтить оставшиеся
UPDATE house_imv_evaluations hie UPDATE house_imv_evaluations hie
SET house_id = m.canonical_id SET house_id = m.canonical_id
FROM _108_dup_mapping m FROM _108_dup_mapping m
WHERE hie.house_id = m.dup_id; WHERE hie.house_id = m.dup_id;
-- 3e. house_suggestions UNIQUE(house_id, ext_item_id) -- 3e. house_suggestions UNIQUE(house_id, ext_item_id)
-- Collision-safe: дедуп по (canonical, ext_item_id) — ловит dup-vs-dup. -- Удалить строки дубля, у которых (ext_item_id) уже есть у canonical.
DELETE FROM house_suggestions t DELETE FROM house_suggestions hs
USING ( USING _108_dup_mapping m
SELECT t2.id, WHERE hs.house_id = m.dup_id
ROW_NUMBER() OVER ( AND EXISTS (
PARTITION BY COALESCE(m.canonical_id, t2.house_id), t2.ext_item_id SELECT 1 FROM house_suggestions hs2
ORDER BY (m.canonical_id IS NULL) DESC, t2.id ASC WHERE hs2.house_id = m.canonical_id
) AS rn AND hs2.ext_item_id = hs.ext_item_id
FROM house_suggestions t2 );
LEFT JOIN _108_dup_mapping m ON m.dup_id = t2.house_id
) d
WHERE t.id = d.id AND d.rn > 1;
-- Репойнтить оставшиеся -- Репойнтить оставшиеся
UPDATE house_suggestions hs UPDATE house_suggestions hs
SET house_id = m.canonical_id SET house_id = m.canonical_id
@ -279,20 +268,7 @@ SET house_id = m.canonical_id
FROM _108_dup_mapping m FROM _108_dup_mapping m
WHERE ev.house_id = m.dup_id; WHERE ev.house_id = m.dup_id;
-- 3i. address_mismatch_audit UNIQUE(house_id, audit_batch) — collision-safe -- 3i. address_mismatch_audit (CASCADE, нет блокирующего UNIQUE)
-- (заголовок ранее ошибочно помечал «нет блокирующего UNIQUE»).
DELETE FROM address_mismatch_audit t
USING (
SELECT t2.id,
ROW_NUMBER() OVER (
PARTITION BY COALESCE(m.canonical_id, t2.house_id), t2.audit_batch
ORDER BY (m.canonical_id IS NULL) DESC, t2.id ASC
) AS rn
FROM address_mismatch_audit t2
LEFT JOIN _108_dup_mapping m ON m.dup_id = t2.house_id
) d
WHERE t.id = d.id AND d.rn > 1;
-- Репойнтить оставшиеся
UPDATE address_mismatch_audit ama UPDATE address_mismatch_audit ama
SET house_id = m.canonical_id SET house_id = m.canonical_id
FROM _108_dup_mapping m FROM _108_dup_mapping m