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:
@@ -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. Это гарантирует, что всегда используется одна и та же запись
|
||||||
|
|
||||||
============================================================================
|
============================================================================
|
||||||
ПРИМЕРЫ ИСПОЛЬЗОВАНИЯ:
|
ПРИМЕРЫ ИСПОЛЬЗОВАНИЯ:
|
||||||
============================================================================
|
============================================================================
|
||||||
|
|||||||
Reference in New Issue
Block a user