← back to Ventura Corridor

db/migrations/015_dupe_merge.sql

34 lines

-- Migration 015 — same-tenant merge + dismiss actions for dupe pairs
-- Adds businesses.merged_into (so a confirmed dupe stops appearing in the roster)
-- Adds dupe_pair_decisions table to remember dismissals (false positives)
-- v_building_canonical now filters merged-out rows.

ALTER TABLE businesses
  ADD COLUMN IF NOT EXISTS merged_into BIGINT REFERENCES businesses(id) ON DELETE SET NULL,
  ADD COLUMN IF NOT EXISTS merged_at   TIMESTAMPTZ;

CREATE INDEX IF NOT EXISTS idx_businesses_merged_into ON businesses (merged_into) WHERE merged_into IS NOT NULL;

-- Decisions on dupe pairs: 'merge' (already actioned) or 'dismiss' (false positive)
CREATE TABLE IF NOT EXISTS dupe_pair_decisions (
  id_a       BIGINT NOT NULL,
  id_b       BIGINT NOT NULL,
  decision   TEXT   NOT NULL CHECK (decision IN ('merge','dismiss')),
  decided_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
  PRIMARY KEY (id_a, id_b),
  CHECK (id_a < id_b)
);

-- Rebuild v_building_canonical to skip merged-out businesses
CREATE OR REPLACE VIEW v_building_canonical AS
SELECT
  b.id, b.name, b.address, b.city, b.zip, b.lat, b.lng, b.phone, b.website,
  b.category, b.category_naics, b.on_corridor,
  TRIM(regexp_replace(b.address, '\s*(SUITE|STE|UNIT|#).*$', '', 'i')) AS bldg_address,
  COALESCE(substring(b.address from '(?:SUITE|STE|UNIT|#)\s*[#]?\s*([A-Z0-9-]+)'), '') AS suite,
  b.raw->>'primary_naics_description' AS naics
FROM businesses b
WHERE b.on_corridor
  AND b.address IS NOT NULL
  AND b.merged_into IS NULL;   -- exclude merged dupes