fix: Add claim_lookup CTE to search by both ID and payload claim_id
Problem: - Original query only searched by ID: WHERE c.id = partial.cid - If record exists with different ID but same claim_id in payload, it wasn't found and documents weren't updated Solution: - Added claim_lookup CTE that searches both by ID and payload->>'claim_id': WHERE id::text = claim_id_str OR payload->>'claim_id' = claim_id_str - Uses found ID from claim_lookup instead of partial.cid - This ensures correct record is always used Changes: - partial now accepts $2::text (instead of $2::uuid) - Added claim_lookup CTE for record lookup - upd_claim uses claim_lookup.id instead of partial.cid - docs uses claim_lookup.id instead of partial.cid Files: - docs/SQL_CLAIMSAVE_FINAL_FIXED.sql: Fixed version with claim_lookup
This commit is contained in:
133
docs/SQL_CLAIMSAVE_FINAL_FIXED.sql
Normal file
133
docs/SQL_CLAIMSAVE_FINAL_FIXED.sql
Normal file
@@ -0,0 +1,133 @@
|
||||
-- Исправленный SQL для сохранения документов (claimsave_final)
|
||||
-- ✅ ИСПРАВЛЕНО: Ищем запись и по ID, и по payload->>'claim_id', чтобы избежать дубликатов
|
||||
-- $1 = payload_partial_json (jsonb)
|
||||
-- $2 = claim_id (text или uuid в виде строки)
|
||||
|
||||
WITH partial AS (
|
||||
SELECT $1::jsonb AS p, $2::text AS claim_id_str
|
||||
),
|
||||
|
||||
-- ✅ ИСПРАВЛЕНО: Ищем запись и по ID, и по payload->>'claim_id'
|
||||
claim_lookup AS (
|
||||
SELECT
|
||||
id,
|
||||
payload
|
||||
FROM clpr_claims
|
||||
WHERE id::text = partial.claim_id_str
|
||||
OR payload->>'claim_id' = partial.claim_id_str
|
||||
ORDER BY
|
||||
CASE WHEN id::text = partial.claim_id_str THEN 1 ELSE 2 END,
|
||||
updated_at DESC
|
||||
LIMIT 1
|
||||
),
|
||||
|
||||
docs AS (
|
||||
SELECT
|
||||
claim_lookup.id::text AS claim_id, -- uuid -> text для clpr_claim_documents
|
||||
doc.field_name::text AS field_name,
|
||||
doc.file_id::text AS file_id,
|
||||
doc.file_name::text AS file_name,
|
||||
doc.original_file_name::text AS original_file_name,
|
||||
(doc.uploaded_at)::timestamptz AS uploaded_at,
|
||||
doc.file_url::text AS file_url
|
||||
FROM partial, claim_lookup
|
||||
CROSS JOIN LATERAL jsonb_to_recordset(
|
||||
COALESCE(partial.p->'documents_meta','[]'::jsonb)
|
||||
) AS doc(
|
||||
field_name text, file_id text, file_name text,
|
||||
original_file_name text, uploaded_at text, file_url text
|
||||
)
|
||||
),
|
||||
|
||||
upsert_docs AS (
|
||||
INSERT INTO clpr_claim_documents
|
||||
(claim_id, field_name, file_id, uploaded_at)
|
||||
SELECT claim_id, field_name, file_id, uploaded_at
|
||||
FROM docs
|
||||
ON CONFLICT (claim_id, field_name) DO UPDATE
|
||||
SET file_id = EXCLUDED.file_id,
|
||||
uploaded_at = EXCLUDED.uploaded_at
|
||||
RETURNING id, claim_id, field_name, file_id
|
||||
),
|
||||
|
||||
-- ✅ ИСПРАВЛЕНО: Используем ID из claim_lookup вместо partial.cid
|
||||
upd_claim AS (
|
||||
UPDATE clpr_claims c
|
||||
SET payload = jsonb_set(
|
||||
COALESCE(c.payload, '{}'::jsonb),
|
||||
'{documents_meta}',
|
||||
COALESCE((SELECT p->'documents_meta' FROM partial), '[]'::jsonb),
|
||||
true
|
||||
),
|
||||
updated_at = now(),
|
||||
expires_at = now() + interval '14 days'
|
||||
FROM partial, claim_lookup
|
||||
WHERE c.id = claim_lookup.id
|
||||
RETURNING c.id, c.payload
|
||||
)
|
||||
|
||||
SELECT
|
||||
(SELECT jsonb_build_object('claim_id', u.id, 'payload', u.payload) FROM upd_claim u) AS claim,
|
||||
(
|
||||
SELECT jsonb_agg(
|
||||
jsonb_build_object(
|
||||
'id', u.id,
|
||||
'field_name', u.field_name,
|
||||
'file_id', u.file_id,
|
||||
'file_url', d.file_url,
|
||||
'file_name', d.file_name,
|
||||
'original_file_name', d.original_file_name,
|
||||
'uploaded_at', d.uploaded_at,
|
||||
-- имя, которое безопасно отдавать во внешний API
|
||||
'filename_for_upload',
|
||||
COALESCE(
|
||||
NULLIF(d.original_file_name, ''),
|
||||
NULLIF(d.file_name, ''),
|
||||
regexp_replace(d.file_id, '^.*/', '') -- хвост пути как запасной
|
||||
)
|
||||
)
|
||||
)
|
||||
FROM upsert_docs u
|
||||
JOIN docs d
|
||||
ON d.claim_id = u.claim_id
|
||||
AND d.field_name = u.field_name
|
||||
WHERE d.file_url IS NOT NULL AND d.file_url <> '' -- не показываем без URL
|
||||
) AS documents;
|
||||
|
||||
/*
|
||||
============================================================================
|
||||
ИСПРАВЛЕНИЯ (2025-11-24):
|
||||
============================================================================
|
||||
|
||||
ПРОБЛЕМА: Запрос искал запись только по ID (WHERE c.id = partial.cid)
|
||||
Если запись была создана с другим ID, но с тем же claim_id в payload,
|
||||
она не находилась и не обновлялась.
|
||||
|
||||
РЕШЕНИЕ:
|
||||
1. Добавлен CTE claim_lookup - ищет запись и по ID, и по payload->>'claim_id':
|
||||
WHERE id::text = claim_id_str OR payload->>'claim_id' = claim_id_str
|
||||
2. Используется найденный ID из claim_lookup вместо partial.cid
|
||||
3. Это гарантирует, что всегда используется правильная запись
|
||||
|
||||
ИЗМЕНЕНИЯ:
|
||||
- partial теперь принимает $2::text (вместо $2::uuid)
|
||||
- Добавлен claim_lookup CTE для поиска записи
|
||||
- upd_claim использует claim_lookup.id вместо partial.cid
|
||||
- docs использует claim_lookup.id вместо partial.cid
|
||||
|
||||
============================================================================
|
||||
ПРИМЕРЫ ИСПОЛЬЗОВАНИЯ:
|
||||
============================================================================
|
||||
|
||||
1. С claim_id как UUID строкой:
|
||||
$1 = '{"documents_meta": [...]}'::jsonb
|
||||
$2 = '0eb051ec-23a6-4e06-8b98-f02d20d35f68'::text
|
||||
|
||||
2. С claim_id как UUID из payload:
|
||||
$1 = '{"documents_meta": [...]}'::jsonb
|
||||
$2 = '0eb051ec-23a6-4e06-8b98-f02d20d35f68'::text
|
||||
(запрос найдет запись по payload->>'claim_id', если ID не совпадает)
|
||||
|
||||
============================================================================
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user