Продолжаю развивать тему по Python. Частая задача в DE (особенно на Spark): один и тот же расчёт нужно прогнать по 2–5 витринам/таблицам и сверить результат.
И вот тут появляются ручные операции:
🎯руками написать 2 запроса (или CTE),
🎯руками прописать имена таблиц/вьюх,
🎯руками подставить даты,
🎯руками собрать вывод и diff,
вероятность допустить ошибку довольно большая.
Идея - Python нужен как каркас:
🎯один раз задаёшь список источников,
🎯один раз парсишь имена,
🎯дальше всё собирается автоматически,
🎯ошибиться становится реально сложнее.
Далее применяется минимальный базовый python (словари, списки, переменные).
1️⃣ Один список источников → структура метаданных
subscribe = [
"core.transactions",
"marts.fct_transactions",
]
meta = {}
for full_name in subscribe:
schema, table = full_name.split(".")
meta[full_name] = {
"schema": schema,
"table": table,
"temp_view": f"df_agg_{table}",
}
# быстро проверить, что получилось
for k, v in meta.items():
print(f"subscribe = {k}")
print(f"table_name = {v['table']}")
print(f"temp_view = {v['temp_view']}")
print()
Вывод будет такой:
subscribe = core.transactions
table_name = transactions
temp_view = df_agg_transactions
subscribe = marts.fct_transactions
table_name = fct_transactions
temp_view = df_agg_fct_transactions
На этом шаге вы парсите схемы, убираете ручные имена из кода.
2️⃣ Логи и паспорта сверки
start_date = "2025-01-01"
end_date = "2025-02-01"
t1_key, t2_key = subscribe[0], subscribe[1]
t1 = meta[t1_key]["table"]
t2 = meta[t2_key]["table"]
v1 = meta[t1_key]["temp_view"]
v2 = meta[t2_key]["temp_view"]
print(
f"Сверка по витринам:\n\n"
f"{t1_key}\n{t2_key}\n\n"
f"start_date = {start_date}\n"
f"end_date = {end_date}\n"
)
print(f"Temp views:\n\n{v1}\n{v2}\n")
3️⃣ Spark SQL собирается через f-string
Здесь суть: мы используем одни и те же правила именования, а не вспоминаем руками, как там называли витрину.
df = spark.sql(f"""
WITH {t1} AS (
SELECT
item,
SUM(col1) AS {t1}_col1,
SUM(col2) AS {t1}_col2
FROM {v1}
WHERE dt >= '{start_date}' AND dt < '{end_date}'
GROUP BY 1
),
{t2} AS (
SELECT
item,
SUM(col1) AS {t2}_col1,
SUM(col2) AS {t2}_col2
FROM {v2}
WHERE dt >= '{start_date}' AND dt < '{end_date}'
GROUP BY 1
)
SELECT
COALESCE({t1}.item, {t2}.item) AS item,
{t1}_col1,
{t1}_col2,
{t2}_col1,
{t2}_col2,
ROUND(({t2}_col1 - {t1}_col1) * 100.0 / NULLIF({t2}_col1, 0), 2) AS diff_perc_col1,
ROUND(({t2}_col2 - {t1}_col2) * 100.0 / NULLIF({t2}_col2, 0), 2) AS diff_perc_col2
FROM {t1}
FULL OUTER JOIN {t2}
ON {t1}.item = {t2}.item
ORDER BY 1
""")
ℹ️ Почему это полезно
Когда ты делаешь сверки/однотипные расчёты, Python даёт 3 вещи:
🎯Снижение ручных операций
Не вводишь руками имена таблиц/вьюх/параметров — они генерируются.
🎯Стабильность и воспроизводимость
Один скрипт — один контракт. Завтра ты сравнишь то же самое, тем же способом.
🎯Масштабирование
Сегодня две витрины, завтра пять — ты добавляешь строку в список, а не копируешь запросы.
❓ Вопрос к тебе:
Какая самая раздражающая ручная операция в твоих задачах?
#материалы