Как мы оформляем наш SQL
Основы
- ☁️ Используйте SQLFluff для автоматического поддержания этих правил стиля.
- Настройте файлы конфигурации
.sqlfluffв соответствии с вашими потребностями. - Обратитесь к нашему файлу конфигурации SQLFluff для правил, которые мы используем в наших проектах.
- Исключайте файлы и директории, используя стандартный файл
.sqlfluffignore. Узнайте больше о синтаксисе в документации по синтаксису .sqlfluffignore.- Исключение ненужных папок и файлов (таких как
target/,dbt_packages/иmacros/) может ускорить проверку, улучшить время выполнения и помочь избежать нерелевантных логов.
- Исключение ненужных папок и файлов (таких как
- Настройте файлы конфигурации
- 👻 Используйте комментарии Jinja (
{# #}) для комментариев, которые не должны быть включены в скомпилированный SQL. - ⏭️ Используйте завершающие запятые.
- 4️⃣ Отступы должны составлять четыре пробела.
- 📏 Строки SQL не должны превышать 80 символов.
- ⬇️ Имена полей, ключевые слова и имена функций должны быть в нижнем регистре.
- 🫧 Ключевое слово
asдолжно использоваться явно при создании псевдонима для поля или таблицы.
к сведению
☁️ Пользователи dbt могут использовать встроенную интеграцию SQLFluff Studio IDE, чтобы автоматически выполнять линтинг и форматирование SQL. Стандартный файл стилей основан на стиле dbt Labs, описанном в этом руководстве, однако вы можете настроить его под свои нужды. Не нужно настраивать какие‑либо внешние инструменты — просто нажмите Lint! Кроме того, если вам ближе более строгий и «мнение‑ориентированный» стиль, доступен форматтер sqlfmt.
Поля, агрегации и группировка
- 🔙 Поля должны быть указаны перед агрегатами и оконными функциями.
- 🤏🏻 Агрегации должны выполняться как можно раньше (на самом маленьком возможном наборе данных) перед объединением с другой таблицей для улучшения производительности.
- 🔢 Предпочтительно упорядочивание и группировка по номеру (например, group by 1, 2) вместо перечисления имен столбцов (см. этот классический пост о том, почему). Обратите внимание, что если вы группируете по более чем нескольким столбцам, возможно, стоит пересмотреть дизайн вашей модели.
Объединения
- 👭🏻 Предпочитайте
union allвместоunion, если вы явно не хотите удалить дубликаты. - 👭🏻 Если объединяете две или более таблиц, всегда добавляйте префикс к именам столбцов с именем таблицы. Если выбираете только из одной таблицы, префиксы не нужны.
- 👭🏻 Будьте явными в отношении типа объединения (т.е. пишите
inner joinвместоjoin). - 🥸 Избегайте псевдонимов таблиц в условиях объединения (особенно инициализмов) — сложнее понять, что такое таблица "c" по сравнению с "customers".
- ➡️ Всегда двигайтесь слева направо, чтобы объединения было легко понять -
right joinsчасто указывают на то, что вам следует изменить, из какой таблицы вы выбираетеfromи к какойjoin.
'Импорт' CTE
- 🔝 Все выражения
{{ ref('...') }}должны быть размещены в CTE в начале файла. - 📦 'Импорт' CTE должны быть названы в честь таблицы, на которую они ссылаются.
- 🤏🏻 Ограничьте объем данных, сканируемых CTE, насколько это возможно. По возможности выбирайте только те столбцы, которые вы действительно используете, и используйте
whereдля фильтрации ненужных данных. - Например:
with
orders as (
select
order_id,
customer_id,
order_total,
order_date
from {{ ref('orders') }}
where order_date >= '2020-01-01'
)
'Функциональные' CTE
- ☝🏻 Если производительность позволяет, CTE должны выполнять одну логическую единицу работы.
- 📖 Имена CTE должны быть настолько подробными, насколько это необходимо, чтобы передать, что они делают, например,
events_joined_to_usersвместоuser_events(это может быть хорошим именем модели, но не описывает конкретную функцию или трансформацию). - 🌉 CTE, которые дублируются в разных моделях, должны быть выделены в собственные промежуточные модели. Обратите внимание на повторяющиеся фрагменты логики, которые следует рефакторить в собственную модель.
- 🔚 Последняя строка модели должна быть
select *из вашего финального выходного CTE. Это упрощает материализацию и аудит выходных данных с разных этапов модели во время ее разработки. Просто измените CTE, на который ссылается операторselect, чтобы увидеть выходные данные с этого этапа.
Конфигурация модели
- 📝 Атрибуты, специфичные для модели (например, ключи сортировки/распределения), должны быть указаны в модели.
- 📂 Если определенная конфигурация применяется ко всем моделям в директории, она должна быть указана в файле
dbt_project.yml. - 👓 Конфигурации в модели должны быть указаны следующим образом для максимальной читаемости:
{{
config(
materialized = 'table',
sort = 'id',
dist = 'id'
)
}}
Пример SQL
with
events as (
...
),
{# CTE комментарии здесь #}
filtered_events as (
...
)
select * from filtered_events
Пример SQL
with
my_data as (
select
field_1,
field_2,
field_3,
cancellation_date,
expiration_date,
start_date
from {{ ref('my_data') }}
),
some_cte as (
select
id,
field_4,
field_5
from {{ ref('some_cte') }}
),
some_cte_agg as (
select
id,
sum(field_4) as total_field_4,
max(field_5) as max_field_5
from some_cte
group by 1
),
joined as (
select
my_data.field_1,
my_data.field_2,
my_data.field_3,
-- используйте разрывы строк для визуального разделения вычислений на блоки
case
when my_data.cancellation_date is null
and my_data.expiration_date is not null
then expiration_date
when my_data.cancellation_date is null
then my_data.start_date + 7
else my_data.cancellation_date
end as cancellation_date,
some_cte_agg.total_field_4,
some_cte_agg.max_field_5
from my_data
left join some_cte_agg
on my_data.id = some_cte_agg.id
where my_data.field_1 = 'abc' and
(
my_data.field_2 = 'def' or
my_data.field_2 = 'ghi'
)
having count(*) > 1
)
select * from joined
Нашли ошибку?
0