Перейти к основному содержимому

Как мы оформляем наш SQL

Основы

  • ☁️ Используйте SQLFluff для автоматического поддержания этих правил стиля.
    • Настройте файлы конфигурации .sqlfluff в соответствии с вашими потребностями.
    • Обратитесь к нашему файлу конфигурации SQLFluff для правил, которые мы используем в наших проектах.
    • Исключайте файлы и директории, используя стандартный файл .sqlfluffignore. Узнайте больше о синтаксисе в документации по синтаксису .sqlfluffignore.
      • Исключение ненужных папок и файлов (таких как target/, dbt_packages/ и macros/) может ускорить проверку, улучшить время выполнения и помочь избежать нерелевантных логов.
  • 👻 Используйте комментарии Jinja ({# #}) для комментариев, которые не должны быть включены в скомпилированный SQL.
  • ⏭️ Используйте завершающие запятые.
  • 4️⃣ Отступы должны составлять четыре пробела.
  • 📏 Строки SQL не должны превышать 80 символов.
  • ⬇️ Имена полей, ключевые слова и имена функций должны быть в нижнем регистре.
  • 🫧 Ключевое слово as должно использоваться явно при создании псевдонима для поля или таблицы.
к сведению

☁️ Пользователи dbt Cloud могут использовать встроенную интеграцию SQLFluff Cloud 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