Files
clickstream-data-platform/sql/dq/events_enriched_vs_dds.sql
T
ddadminandClaude Fable 5 f33d75113d feat(dm): добавлены учебные задания витрин и даг самопроверки
- Зачем:
  - менти строит витрины DM сам, от DDL по правилу зерна до задачи в
    конвейере; стенду нужны ТЗ с образцом и обратная связь по каждой
    витрине (#159, резолюция #135).
- Что:
  - docs/labs/: README и пять ТЗ — events_enriched_v, top_pages_daily,
    session_overview, dq_errors_daily, utm_effectiveness; каждое ТЗ
    называет урок, состав колонок, форму по зерну и самопроверку.
  - dags/homework_check.py: ручной даг, задача на витрину, красная без
    витрины или при расхождении; проверки — шесть файлов sql/dq/ с
    инвариантами против DDS и ODS, без золотых констант; в dq_summary
    не пишет.
  - docs: dm.md называет homework_check и снимает «Остается нарезке»,
    §7 и §10 мастер-спеки согласованы с лабами, dds/session.md указывает
    на ТЗ, AGENTS.md пополнен правилом имен docs/labs/.
- Проверка:
  - make lint; make smoke 21/21, make check-clickhouse 10/10,
    make check-services 7/7.
  - на свежем стенде все пять задач homework_check красные и называют
    ТЗ; черновик каждой витрины по тексту ТЗ зеленит свою задачу,
    после сноса — снова красная; строк от самопроверки в dq_summary нет.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-27 17:44:15 -04:00

126 lines
3.8 KiB
SQL

-- DQ: обогащенные события против прямого ответа DDS за один день.
--
-- День передает даг, чтобы широкая сверка не собирала всю историю в памяти.
WITH
reference AS
(
SELECT
event_date,
event_id,
tuple(
event_time,
toHour(event_time),
client_id,
event_type,
url,
path(url),
referer,
domain(referer),
title,
utm_source,
utm_medium,
utm_campaign,
utm_content,
utm_term,
device_category,
browser,
operating_system,
region_country,
region_city,
product_id,
product_name,
product_category,
product_price,
product_quantity,
product_event_type,
purchase_id,
purchase_revenue,
purchase_coupon
) AS value
FROM dds.event_v
WHERE event_date = {day:Date}
),
actual AS
(
SELECT
event_date,
event_id,
count() AS physical_rows,
any(tuple(
event_time,
event_hour,
client_id,
event_type,
url,
page_path,
referer,
referer_host,
title,
utm_source,
utm_medium,
utm_campaign,
utm_content,
utm_term,
device_category,
browser,
operating_system,
region_country,
region_city,
product_id,
product_name,
product_category,
product_price,
product_quantity,
product_event_type,
purchase_id,
purchase_revenue,
purchase_coupon
)) AS value
FROM dm.events_enriched_v
WHERE event_date = {day:Date}
GROUP BY event_date, event_id
),
comparison AS
(
SELECT
coalesce(reference.event_date, actual.event_date) AS data_date,
coalesce(reference.event_id, actual.event_id) AS business_key,
isNotNull(reference.event_id) AS reference_present,
isNotNull(actual.event_id) AS actual_present,
reference.value AS reference_value,
actual.value AS actual_value,
actual.physical_rows AS physical_rows,
isNull(reference.event_id)
OR isNull(actual.event_id)
OR actual.physical_rows != 1
OR NOT isNotDistinctFrom(reference.value, actual.value) AS failed
FROM reference
GLOBAL FULL OUTER JOIN actual USING (event_date, event_id)
)
SELECT
data_date,
countIf(reference_present) AS reference_rows,
countIf(actual_present) AS actual_rows,
countIf(failed) AS failed_rows,
groupArrayIf(20)(
concat(
toString(data_date),
' event_id=',
toString(business_key),
': источник=',
if(reference_present, toString(reference_value), 'нет ключа'),
', витрина=',
if(
actual_present,
concat(toString(actual_value), ', rows=', toString(physical_rows)),
'нет ключа'
)
),
failed
) AS diagnostics
FROM comparison
GROUP BY data_date
ORDER BY data_date
SETTINGS join_use_nulls = 1