From 81963d18c37ac65dca6d77c7516a8f63ecc7d5b4 Mon Sep 17 00:00:00 2001 From: AI Assistant Date: Mon, 24 Nov 2025 16:52:58 +0300 Subject: [PATCH] fix: Prevent duplicate claims by searching both by ID and payload claim_id Problem: - Multiple records created with same claim_id but different IDs - Example: ID=0eb051ec... (correct) vs ID=b532b1b3... (duplicate) - Different SQL queries used different approaches: * Some used claim_id as UUID for ID (partial.claim_id_str::uuid) * Others searched by payload->>'claim_id' and created new UUID if not found Root Cause: - SQL_CLAIMSAVE_UPSERT_SIMPLE.sql only searched by ID: WHERE id = claim_id_str::uuid - If record existed with different ID but same claim_id in payload, it wasn't found and new record was created Solution: 1. existing_claim now searches both by ID and payload->>'claim_id': WHERE id = claim_id_str::uuid OR payload->>'claim_id' = claim_id_str ORDER BY priority (ID match first), then updated_at DESC 2. INSERT uses ID from existing_claim if found: COALESCE((SELECT id FROM existing_claim), partial.claim_id_str::uuid) 3. This ensures same record is always used, preventing duplicates Files: - docs/SQL_CLAIMSAVE_UPSERT_SIMPLE.sql: Fixed search logic and INSERT ID --- docs/SQL_CLAIMSAVE_UPSERT_SIMPLE.sql | 29 ++++++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/docs/SQL_CLAIMSAVE_UPSERT_SIMPLE.sql b/docs/SQL_CLAIMSAVE_UPSERT_SIMPLE.sql index 6292b7e..98c5f9f 100644 --- a/docs/SQL_CLAIMSAVE_UPSERT_SIMPLE.sql +++ b/docs/SQL_CLAIMSAVE_UPSERT_SIMPLE.sql @@ -15,12 +15,17 @@ WITH partial AS ( ), -- Получаем существующий payload из БД (если запись есть) +-- ✅ ИСПРАВЛЕНО: Ищем и по ID, и по payload->>'claim_id', чтобы избежать дубликатов existing_claim AS ( SELECT id, payload FROM clpr_claims WHERE id = (SELECT claim_id_str::uuid FROM partial) + OR payload->>'claim_id' = (SELECT claim_id_str FROM partial) + ORDER BY + CASE WHEN id = (SELECT claim_id_str::uuid FROM partial) THEN 1 ELSE 2 END, + updated_at DESC LIMIT 1 ), @@ -143,6 +148,7 @@ problem_description_parsed AS ( ), -- UPSERT claim +-- ✅ ИСПРАВЛЕНО: Используем ID из existing_claim, если он найден, чтобы избежать дубликатов claim_upsert AS ( INSERT INTO clpr_claims ( id, @@ -159,7 +165,10 @@ claim_upsert AS ( expires_at ) SELECT - partial.claim_id_str::uuid, + COALESCE( + (SELECT id FROM existing_claim), + partial.claim_id_str::uuid + ), COALESCE( partial.p->>'session_id', partial.p->'edit_fields_parsed'->'body'->>'session_id', @@ -202,7 +211,7 @@ claim_upsert AS ( 'email', COALESCE(partial.p->>'email', (SELECT payload->>'email' FROM existing_claim)) ), COALESCE( - (SELECT created_at FROM clpr_claims WHERE id = partial.claim_id_str::uuid), + (SELECT created_at FROM existing_claim), now() ), now(), @@ -289,6 +298,22 @@ SELECT 3. Это критично для workflow form_get, где wizard_plan создаётся на Step 2, а файлы загружаются на Step 3 (без повторной отправки wizard_plan) +============================================================================ +ИСПРАВЛЕНИЕ ДУБЛИКАТОВ (2025-11-24): +============================================================================ + +ПРОБЛЕМА: Создавались дубликаты записей с одинаковым claim_id, но разными ID +Причина: Разные SQL запросы использовали разные подходы: + - Одни использовали claim_id как UUID для ID (partial.claim_id_str::uuid) + - Другие искали по payload->>'claim_id' и создавали новый UUID, если не находили + +РЕШЕНИЕ: +1. existing_claim теперь ищет и по ID, и по payload->>'claim_id': + WHERE id = claim_id_str::uuid OR payload->>'claim_id' = claim_id_str +2. INSERT использует ID из existing_claim, если он найден: + COALESCE((SELECT id FROM existing_claim), partial.claim_id_str::uuid) +3. Это гарантирует, что всегда используется одна и та же запись + ============================================================================ ПРИМЕРЫ ИСПОЛЬЗОВАНИЯ: ============================================================================