From 6ce79158067035dc0e72e4b00c1ef9f76caba872 Mon Sep 17 00:00:00 2001 From: Dmitry Dementev Date: Sun, 18 Jan 2026 22:24:06 +0300 Subject: [PATCH] =?UTF-8?q?=D0=A3=D0=BB=D1=83=D1=87=D1=88=D0=B5=D0=BD?= =?UTF-8?q?=D0=B8=D0=B5=20DQ=20=D0=BF=D1=80=D0=BE=D0=B2=D0=B5=D1=80=D0=BA?= =?UTF-8?q?=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/internal/bookings_stg_code_review.md | 10 ++++++---- sql/stg/boarding_passes_dq.sql | 3 ++- sql/stg/routes_dq.sql | 3 ++- sql/stg/seats_dq.sql | 3 ++- sql/stg/segments_dq.sql | 3 ++- 5 files changed, 14 insertions(+), 8 deletions(-) diff --git a/docs/internal/bookings_stg_code_review.md b/docs/internal/bookings_stg_code_review.md index ba261c0..3e33530 100644 --- a/docs/internal/bookings_stg_code_review.md +++ b/docs/internal/bookings_stg_code_review.md @@ -104,12 +104,14 @@ WHERE NOT EXISTS ( Что сделано: - В `sql/stg/*_load.sql` комментарии приведены к формулировке “идемпотентность при повторном запуске/ретрае”. -### 3.3. Проверка составных ключей: избегать склейки строк +### 3.3. Проверка составных ключей: избегать склейки строк (статус: исправлено) Паттерн вида `COUNT(DISTINCT col1 || '|' || col2)` теоретически может давать коллизии (если в данных встречается разделитель). -В учебном стенде риск небольшой, но как “эталон” лучше показывать более безопасный подход: -- если поддерживается: `COUNT(DISTINCT (col1, col2))`; -- либо использовать стабильную сериализацию, где коллизии исключены (например, `md5(...)` от безопасной структуры). +В учебном стенде риск небольшой, но как “эталон” лучше показывать более безопасный подход. + +Что сделано: +- Заменили склейку строк на `COUNT(DISTINCT md5(ROW(col1, col2)::text))` в DQ‑скриптах для составных ключей. + Такой подход сохраняет DV‑стиль и убирает неоднозначность разделителей. --- diff --git a/sql/stg/boarding_passes_dq.sql b/sql/stg/boarding_passes_dq.sql index 0a2f123..6fcf686 100644 --- a/sql/stg/boarding_passes_dq.sql +++ b/sql/stg/boarding_passes_dq.sql @@ -36,7 +36,8 @@ BEGIN END IF; -- Проверка на дубликаты (ticket_no, flight_id) - SELECT COUNT(*) - COUNT(DISTINCT ticket_no || '|' || flight_id) + -- Используем md5 от ROW, чтобы избежать коллизий при склейке строк. + SELECT COUNT(*) - COUNT(DISTINCT md5(ROW(ticket_no, flight_id)::text)) INTO v_dup_count FROM stg.boarding_passes AS bp WHERE bp.batch_id = v_batch_id; diff --git a/sql/stg/routes_dq.sql b/sql/stg/routes_dq.sql index 23a0e86..6f011aa 100644 --- a/sql/stg/routes_dq.sql +++ b/sql/stg/routes_dq.sql @@ -34,7 +34,8 @@ BEGIN END IF; -- Проверка на дубликаты составного ключа (route_no, validity) - SELECT COUNT(*) - COUNT(DISTINCT route_no || '|' || validity) + -- Используем md5 от ROW, чтобы избежать коллизий при склейке строк. + SELECT COUNT(*) - COUNT(DISTINCT md5(ROW(route_no, validity)::text)) INTO v_dup_count FROM stg.routes AS r WHERE r.batch_id = v_batch_id; diff --git a/sql/stg/seats_dq.sql b/sql/stg/seats_dq.sql index 4b70b81..69296f3 100644 --- a/sql/stg/seats_dq.sql +++ b/sql/stg/seats_dq.sql @@ -33,7 +33,8 @@ BEGIN END IF; -- Проверка на дубликаты составного ключа (airplane_code, seat_no) - SELECT COUNT(*) - COUNT(DISTINCT airplane_code || '|' || seat_no) + -- Используем md5 от ROW, чтобы избежать коллизий при склейке строк. + SELECT COUNT(*) - COUNT(DISTINCT md5(ROW(airplane_code, seat_no)::text)) INTO v_dup_count FROM stg.seats AS s WHERE s.batch_id = v_batch_id; diff --git a/sql/stg/segments_dq.sql b/sql/stg/segments_dq.sql index d59ddf4..feb0aa1 100644 --- a/sql/stg/segments_dq.sql +++ b/sql/stg/segments_dq.sql @@ -62,7 +62,8 @@ BEGIN END IF; -- Проверка на дубликаты (ticket_no, flight_id) - SELECT COUNT(*) - COUNT(DISTINCT ticket_no || '|' || flight_id) + -- Используем md5 от ROW, чтобы избежать коллизий при склейке строк. + SELECT COUNT(*) - COUNT(DISTINCT md5(ROW(ticket_no, flight_id)::text)) INTO v_dup_count FROM stg.segments AS s WHERE s.batch_id = v_batch_id;