From b3826f47cbb56906303ce30d24c56801ccc2be49 Mon Sep 17 00:00:00 2001 From: Dmitry Dementev Date: Sat, 21 Feb 2026 19:21:39 +0300 Subject: [PATCH] =?UTF-8?q?fix(modeling):=20=D0=BF=D1=80=D0=B8=D0=BC=D0=B5?= =?UTF-8?q?=D1=80=20=D0=B2=D0=B8=D1=82=D1=80=D0=B8=D0=BD=D1=8B=20=D0=B2=20?= =?UTF-8?q?README=20=D0=BF=D1=80=D0=B8=D0=B2=D0=B5=D0=B4=D1=91=D0=BD=20?= =?UTF-8?q?=D0=B2=20=D1=81=D0=BE=D0=BE=D1=82=D0=B2=D0=B5=D1=82=D1=81=D1=82?= =?UTF-8?q?=D0=B2=D0=B8=D0=B5=20=D1=81=D0=BE=20=D1=81=D0=BA=D1=80=D0=B8?= =?UTF-8?q?=D0=BF=D1=82=D0=B0=D0=BC=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - customer_segment: убрана несуществующая колонка dim_customer, заменена на CASE по сумме (как в 06_dml_dm.sql) - MATERIALIZED VIEW заменён на TRUNCATE + INSERT INTO (как в скриптах), упоминание MV оставлено в ремарке - добавлен комментарий о недетерминированности CURRENT_DATE в bounds Co-Authored-By: Claude Opus 4.6 --- dwh-modeling/README.md | 21 ++++++++++++------- .../09_dml_hw_customer_status_solution.sql | 2 ++ 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/dwh-modeling/README.md b/dwh-modeling/README.md index a4d038e..b28d9cc 100644 --- a/dwh-modeling/README.md +++ b/dwh-modeling/README.md @@ -544,11 +544,17 @@ flowchart TD ```sql -- mart_daily_sales: ежедневные продажи с сегментацией -CREATE MATERIALIZED VIEW dm.mart_daily_sales AS +-- Полная пересборка (full refresh) - для простоты; в продакшене бывает incremental. +TRUNCATE dm.mart_daily_sales; + +INSERT INTO dm.mart_daily_sales ( + date_actual, product_name, customer_segment, total_qty, total_revenue +) SELECT - d.date_actual AS order_date, + d.date_actual, p.product_name, - c.customer_segment, -- например: 'Premium', 'Basic' + -- Сегмент определяем по сумме строки (в реальности может быть атрибутом клиента) + CASE WHEN f.amount >= 200 THEN 'Premium' ELSE 'Basic' END AS customer_segment, SUM(f.quantity) AS total_qty, SUM(f.amount) AS total_revenue FROM dds.fact_sales f @@ -557,13 +563,12 @@ JOIN dds.dim_date d JOIN dds.dim_product p ON f.product_sk = p.product_sk JOIN dds.dim_customer c - ON f.customer_sk = c.customer_sk - AND d.date_actual >= c.valid_from - AND (c.valid_to IS NULL OR d.date_actual < c.valid_to) -- SCD! -GROUP BY d.date_actual, p.product_name, c.customer_segment; + ON f.customer_sk = c.customer_sk -- факт ссылается на нужную версию SK +GROUP BY d.date_actual, p.product_name, + CASE WHEN f.amount >= 200 THEN 'Premium' ELSE 'Basic' END; ``` -> 💡 **Материализованное представление (MATERIALIZED VIEW)** — это «кэш» результата. Обновляется по расписанию (например, ночью). +> 💡 В продакшене витрину иногда оформляют как **MATERIALIZED VIEW** - «кэш» результата запроса, который обновляется по расписанию. В нашем примере используем обычную таблицу с `TRUNCATE` + `INSERT` - для учебных целей это нагляднее. ✏️ **Попробуйте сами:** [Домашка: статусы клиента от STG до DDS (и немного DM)](Homework_Customer_Status_DDS_DM.md) — пройдёте тот же путь, но самостоятельно. diff --git a/dwh-modeling/sql/09_dml_hw_customer_status_solution.sql b/dwh-modeling/sql/09_dml_hw_customer_status_solution.sql index 42686d8..caba2a0 100644 --- a/dwh-modeling/sql/09_dml_hw_customer_status_solution.sql +++ b/dwh-modeling/sql/09_dml_hw_customer_status_solution.sql @@ -311,6 +311,8 @@ WITH bounds AS ( min(valid_from) AS date_from, -- CURRENT_DATE для открытых интервалов (valid_to IS NULL = текущий статус), -- иначе витрина не покроет даты после последней смены статуса. + -- Нюанс: количество строк в витрине зависит от даты запуска (каждый + -- день добавляется ещё один день). Для учебных целей это приемлемо. max(coalesce(valid_to, CURRENT_DATE)) AS date_to FROM dds.dim_customer_status )