diff --git a/SCD.md b/SCD.md
index cac5851..f4cefa6 100644
--- a/SCD.md
+++ b/SCD.md
@@ -243,6 +243,8 @@ WHERE customer_id = 1 AND is_current = true
Пример в Trino/Hive-стиле (только INSERT):
+Давайте разберём этот запрос по шагам, чтобы понять его логику:
+
```sql
-- new_customers — staging-таблица с обновлёнными данными
-- dim_customers_scd2 — основная таблица (append-only)
@@ -253,7 +255,7 @@ WITH current_customers AS (
FROM (
SELECT *, ROW_NUMBER() OVER (PARTITION BY customer_id ORDER BY valid_from DESC) AS rn
FROM dim_customers_scd2
- )
+ )
WHERE rn = 1 -- отбираем первую, самую свежую, запись
)
SELECT
@@ -261,12 +263,109 @@ SELECT
n.customer_id, -- неизменный бизнес-ID клиента
n.name,
n.category,
- valid_from
+ COALESCE(n.effective_date, current_date) AS valid_from -- дата начала действия новой версии
FROM new_customers n
LEFT JOIN current_customers c ON n.customer_id = c.customer_id
WHERE c.customer_id IS NULL OR c.category != n.category; -- условие верно, если какие-то из полей справочника поменялись
```
+### 🎯 Как работает этот запрос: пошаговое объяснение
+
+```mermaid
+graph TD
+ A[new_customers
новые данные] --> B[CTE: current_customers]
+ C[dim_customers_scd2
текущее состояние] --> B
+ B --> D[LEFT JOIN по customer_id]
+ A --> D
+ D --> E{Условие WHERE}
+ E -->|Новый клиент| F[Вставить запись]
+ E -->|Изменения| F
+ E -->|Без изменений| G[Пропустить]
+ F --> H[dim_customers_scd2
обновленная таблица]
+```
+
+#### Шаг 1: Подготовка данных (CTE current_customers)
+CTE `current_customers` находит **последнюю версию** каждого клиента из таблицы `dim_customers_scd2`:
+
+```sql
+SELECT *, ROW_NUMBER() OVER (PARTITION BY customer_id ORDER BY valid_from DESC) AS rn
+FROM dim_customers_scd2
+```
+
+- `PARTITION BY customer_id` — группируем по клиентам
+- `ORDER BY valid_from DESC` — сортируем версии от самой новой к самой старой
+- `WHERE rn = 1` — выбираем только самую свежую версию
+
+#### Шаг 2: Сравнение данных (LEFT JOIN + WHERE)
+Теперь сравниваем новые данные с текущими:
+
+```sql
+FROM new_customers n
+LEFT JOIN current_customers c ON n.customer_id = c.customer_id
+```
+
+**Возможные сценарии после JOIN:**
+
+| Сценарий | n.customer_id | c.customer_id | Условие WHERE | Результат |
+|----------|---------------|---------------|---------------|-----------|
+| Новый клиент | 2 | NULL | ✅ `c.customer_id IS NULL` | Вставляется |
+| Категория изменилась | 1 | 1 | ✅ `c.category != n.category` | Вставляется |
+| Без изменений | 3 | 3 | ❌ оба условия ложны | Пропускается |
+
+#### Шаг 3: Вставка новых версий
+Для подходящих записей создаём новую версию:
+- `uuid()` — генерируем уникальный ключ для новой версии (функция, скобки обязательны)
+- `COALESCE(n.effective_date, current_date)` — устанавливаем дату начала действия новой версии
+
+> 💡 **Синтаксическая поправка**:
+> - `current_date` — это ключевое слово, а не функция, поэтому скобки не нужны
+> - `uuid()` — это функция, поэтому скобки обязательны
+> - Разница: `current_date` возвращает текущую дату, `uuid()` генерирует уникальный идентификатор
+
+> 💡 **Правильный подход к датам**: В реальных ETL-процессах важно использовать дату из исходных данных, когда она доступна. Мы используем `COALESCE(n.effective_date, current_date)`, что означает:
+> - Если в `new_customers` есть поле `effective_date` — используем его
+> - Если нет — используем текущую дату (`current_date`)
+>
+> **Почему это важно:**
+> - `effective_date` отражает реальную дату изменения (например, когда клиент стал VIP)
+> - `current_date` — это дата загрузки данных, которая может не совпадать с датой изменения
+> - Использование правильной даты критично для точного исторического анализа
+>
+> **Пример правильной структуры исходных данных:**
+> ```sql
+> new_customers:
+> customer_id | name | category | effective_date
+> 1 | Иван Петров | VIP | 2025-04-15 ← дата реального изменения
+> ```
+
+#### Практический пример
+
+**До выполнения запроса:**
+```
+dim_customers_scd2:
+customer_id | name | category | valid_from
+1 | Иван Петров | Regular | 2024-01-01
+```
+
+**Новые данные:**
+```
+new_customers:
+customer_id | name | category
+1 | Иван Петров | VIP ← изменилась категория
+2 | Мария Иванова| Regular ← новый клиент
+```
+
+**После выполнения запроса:**
+```
+dim_customers_scd2:
+customer_id | name | category | valid_from
+1 | Иван Петров | Regular | 2024-01-01 ← старая версия
+1 | Иван Петров | VIP | 2025-11-04 ← новая версия
+2 | Мария Иванова| Regular | 2025-11-04 ← новый клиент
+```
+
+> 💡 **Ключевой момент**: В append-only системах мы **не обновляем** старые записи, а только **добавляем новые**. История сохраняется автоматически!
+
**Главный вопрос после загрузки: как же читать эти данные?**
Поскольку мы не можем обновлять `valid_to` у предыдущей версии (у неё останется `NULL`), стандартный подход с `BETWEEN` не сработает. Вместо этого, для поиска нужной версии мы полагаемся на **оконные функции** или на логику «ближайшей даты, но не позже».
@@ -278,14 +377,14 @@ WHERE c.customer_id IS NULL OR c.category != n.category; -- условие ве
```sql
-- Вариант с оконной функцией (универсальный и надежный)
WITH ranked AS (
- SELECT
- *,
+ SELECT
+ *,
ROW_NUMBER() OVER (PARTITION BY customer_id ORDER BY valid_from DESC) AS rn
- FROM customers_scd2
+ FROM dim_customers_scd2
)
-SELECT
+SELECT
customer_id, name, category, valid_from
-FROM ranked
+FROM ranked
WHERE rn = 1;
```
@@ -300,15 +399,15 @@ WHERE rn = 1;
```sql
-- Запрос для получения состояния на '2025-03-15'
WITH as_of_date AS (
- SELECT
+ SELECT
*,
ROW_NUMBER() OVER (PARTITION BY customer_id ORDER BY valid_from DESC) AS rn
- FROM customers_scd2
+ FROM dim_customers_scd2
WHERE valid_from <= DATE '2025-03-15'
)
-SELECT
+SELECT
customer_id, name, category, valid_from
-FROM as_of_date
+FROM as_of_date
WHERE rn = 1;
```
@@ -360,6 +459,3 @@ WHERE rn = 1;
И помните: даже в системах без `UPDATE` вы можете хранить полную историю — достаточно понимать, как правильно читать данные с помощью оконных функций и временных границ.
----
-
-Готово! Статья теперь включает полный цикл: от концепции — к реализации в традиционной СУБД — и далее к адаптации для современных аналитических платформ.
\ No newline at end of file