fix(modeling): исправлены ошибки по результатам перекрёстного ревью
- Зачем: - в статье и скриптах обнаружены фактические ошибки и несостыковки - Что: - README: f.order_date -> d.date_actual в примере витрины (колонки order_date нет в fact_sales) - README: «календарь на 10 лет» -> «5 лет» (соответствует генерации 2023-2027 в скрипте) - 09_solution: bounds CTE теперь использует CURRENT_DATE для открытых интервалов (valid_to IS NULL) - 09_solution: комментарий про дубли в STG при повторном запуске блока 3 - 05_ddl_dm: выравнивание total_line_items - AGENTS.md: обновлён диапазон скриптов 01-09 - Проверка: - визуальная проверка diff Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
## Project Structure & Module Organization
|
## Project Structure & Module Organization
|
||||||
- Root `README.md` describes the learning roadmap (RU).
|
- Root `README.md` describes the learning roadmap (RU).
|
||||||
- `dwh-modeling/` contains the article and demo DWH model; SQL lives in `dwh-modeling/sql` as ordered scripts `01_...sql`–`06_...sql`.
|
- `dwh-modeling/` contains the article and demo DWH model; SQL lives in `dwh-modeling/sql` as ordered scripts `01_...sql`–`09_...sql` (07–09 are homework DDL, template and solution).
|
||||||
- `postgres-bookings/` is a Dockerized PostgreSQL + demo “bookings” DB; start it first, then apply DWH scripts against the `demo` database.
|
- `postgres-bookings/` is a Dockerized PostgreSQL + demo “bookings” DB; start it first, then apply DWH scripts against the `demo` database.
|
||||||
|
|
||||||
## Build, Test, and Development Commands
|
## Build, Test, and Development Commands
|
||||||
|
|||||||
@@ -180,7 +180,7 @@ flowchart TD
|
|||||||
|---------|------------|
|
|---------|------------|
|
||||||
| `dds.dim_customer` | Измерение «Клиент» с историей (SCD Type 2) |
|
| `dds.dim_customer` | Измерение «Клиент» с историей (SCD Type 2) |
|
||||||
| `dds.dim_product` | Измерение «Товар» |
|
| `dds.dim_product` | Измерение «Товар» |
|
||||||
| `dds.dim_date` | Готовый календарь на 10 лет вперёд (день/неделя/месяц/квартал) |
|
| `dds.dim_date` | Готовый календарь на 5 лет вперёд (день/неделя/месяц/квартал) |
|
||||||
| `dds.fact_sales` | Факт «Продажа» — строка заказа с суммой и количеством |
|
| `dds.fact_sales` | Факт «Продажа» — строка заказа с суммой и количеством |
|
||||||
|
|
||||||
💡 **Суррогатный ключ (Surrogate Key, SK)** — это `BIGINT`, который мы генерируем сами (например, `customer_sk = 1001`).
|
💡 **Суррогатный ключ (Surrogate Key, SK)** — это `BIGINT`, который мы генерируем сами (например, `customer_sk = 1001`).
|
||||||
@@ -558,8 +558,8 @@ JOIN dds.dim_product p
|
|||||||
ON f.product_sk = p.product_sk
|
ON f.product_sk = p.product_sk
|
||||||
JOIN dds.dim_customer c
|
JOIN dds.dim_customer c
|
||||||
ON f.customer_sk = c.customer_sk
|
ON f.customer_sk = c.customer_sk
|
||||||
AND f.order_date >= c.valid_from
|
AND d.date_actual >= c.valid_from
|
||||||
AND (c.valid_to IS NULL OR f.order_date < c.valid_to) -- SCD!
|
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;
|
GROUP BY d.date_actual, p.product_name, c.customer_segment;
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ CREATE TABLE dm.mart_customer_360 (
|
|||||||
customer_bk INT NOT NULL,
|
customer_bk INT NOT NULL,
|
||||||
first_order_date DATE,
|
first_order_date DATE,
|
||||||
last_order_date DATE,
|
last_order_date DATE,
|
||||||
total_line_items INT NOT NULL,
|
total_line_items INT NOT NULL,
|
||||||
total_items INT NOT NULL,
|
total_items INT NOT NULL,
|
||||||
lifetime_value NUMERIC(18,2) NOT NULL,
|
lifetime_value NUMERIC(18,2) NOT NULL,
|
||||||
last_email VARCHAR(100),
|
last_email VARCHAR(100),
|
||||||
|
|||||||
@@ -147,6 +147,10 @@ SELECT * FROM dds.dim_customer_status ORDER BY customer_bk, valid_from;
|
|||||||
-- - клиент 104: новый клиент, статус new
|
-- - клиент 104: новый клиент, статус new
|
||||||
|
|
||||||
-- 3.0) Новые события в STG
|
-- 3.0) Новые события в STG
|
||||||
|
-- При повторном запуске эти строки добавятся в STG ещё раз (дубли).
|
||||||
|
-- Для демо это не страшно: ODS-вставка ниже использует ON CONFLICT DO NOTHING,
|
||||||
|
-- а SCD2-блок защищён от повторных вставок через NOT EXISTS.
|
||||||
|
-- В продакшене STG обычно очищается перед каждой загрузкой (TRUNCATE / партиция по дате).
|
||||||
INSERT INTO stg.customer_status_raw (customer_id, status, event_ts, _load_id, _load_ts) VALUES
|
INSERT INTO stg.customer_status_raw (customer_id, status, event_ts, _load_id, _load_ts) VALUES
|
||||||
('101','active','2024-11-15 09:00:00','batch_20241115_1000','2024-11-15 10:00:00'),
|
('101','active','2024-11-15 09:00:00','batch_20241115_1000','2024-11-15 10:00:00'),
|
||||||
('102','active','2024-05-05 09:30:00','batch_20240505_1000','2024-05-05 10:00:00'),
|
('102','active','2024-05-05 09:30:00','batch_20240505_1000','2024-05-05 10:00:00'),
|
||||||
@@ -305,7 +309,9 @@ TRUNCATE dm.mart_customer_status_daily;
|
|||||||
WITH bounds AS (
|
WITH bounds AS (
|
||||||
SELECT
|
SELECT
|
||||||
min(valid_from) AS date_from,
|
min(valid_from) AS date_from,
|
||||||
max(coalesce(valid_to, valid_from)) AS date_to
|
-- CURRENT_DATE для открытых интервалов (valid_to IS NULL = текущий статус),
|
||||||
|
-- иначе витрина не покроет даты после последней смены статуса.
|
||||||
|
max(coalesce(valid_to, CURRENT_DATE)) AS date_to
|
||||||
FROM dds.dim_customer_status
|
FROM dds.dim_customer_status
|
||||||
)
|
)
|
||||||
INSERT INTO dm.mart_customer_status_daily (
|
INSERT INTO dm.mart_customer_status_daily (
|
||||||
|
|||||||
Reference in New Issue
Block a user