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
This commit is contained in:
AI Assistant
2025-11-24 16:52:58 +03:00
parent 894463742f
commit 81963d18c3

View File

@@ -15,12 +15,17 @@ WITH partial AS (
), ),
-- Получаем существующий payload из БД (если запись есть) -- Получаем существующий payload из БД (если запись есть)
-- ✅ ИСПРАВЛЕНО: Ищем и по ID, и по payload->>'claim_id', чтобы избежать дубликатов
existing_claim AS ( existing_claim AS (
SELECT SELECT
id, id,
payload payload
FROM clpr_claims FROM clpr_claims
WHERE id = (SELECT claim_id_str::uuid FROM partial) 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 LIMIT 1
), ),
@@ -143,6 +148,7 @@ problem_description_parsed AS (
), ),
-- UPSERT claim -- UPSERT claim
-- ✅ ИСПРАВЛЕНО: Используем ID из existing_claim, если он найден, чтобы избежать дубликатов
claim_upsert AS ( claim_upsert AS (
INSERT INTO clpr_claims ( INSERT INTO clpr_claims (
id, id,
@@ -159,7 +165,10 @@ claim_upsert AS (
expires_at expires_at
) )
SELECT SELECT
partial.claim_id_str::uuid, COALESCE(
(SELECT id FROM existing_claim),
partial.claim_id_str::uuid
),
COALESCE( COALESCE(
partial.p->>'session_id', partial.p->>'session_id',
partial.p->'edit_fields_parsed'->'body'->>'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)) 'email', COALESCE(partial.p->>'email', (SELECT payload->>'email' FROM existing_claim))
), ),
COALESCE( COALESCE(
(SELECT created_at FROM clpr_claims WHERE id = partial.claim_id_str::uuid), (SELECT created_at FROM existing_claim),
now() now()
), ),
now(), now(),
@@ -289,6 +298,22 @@ SELECT
3. Это критично для workflow form_get, где wizard_plan создаётся на Step 2, 3. Это критично для workflow form_get, где wizard_plan создаётся на Step 2,
а файлы загружаются на Step 3 (без повторной отправки wizard_plan) а файлы загружаются на 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. Это гарантирует, что всегда используется одна и та же запись
============================================================================ ============================================================================
ПРИМЕРЫ ИСПОЛЬЗОВАНИЯ: ПРИМЕРЫ ИСПОЛЬЗОВАНИЯ:
============================================================================ ============================================================================