Конфигурация seeds
В предыдущем уроке dbt seed работал «магически»: положил CSV -> получил таблицу. На практике каждый второй CSV требует тюнинга. dbt угадывает типы по содержимому, и иногда угадывает неправильно — почтовый индекс 01234 превращается в integer 1234, ведущий ноль теряется. Дата 2026-05-19 остаётся VARCHAR’ом. Колонка is_active со значениями true/false становится строкой, а не boolean.
Чтобы это исправить, у seeds есть набор конфигов, которые задаются через dbt_project.yml или индивидуальный YAML-файл рядом с CSV.
Где конфигурируется seed
Два места:
- В
dbt_project.ymlпод секциейseeds:— для дефолтов и групповых настроек. - В YAML-файле рядом с CSV (например,
seeds/_seeds.yml) — для индивидуальных настроек, descriptions, тестов.
Иерархия:
Самый специфичный конфиг побеждает.
column_types — точное указание типов
Это самая частая причина проблем с seed. dbt по умолчанию проходится по CSV и для каждой колонки выбирает «самый подходящий» тип. Логика проста:
- Все значения — целые числа -> INTEGER (BIGINT в DuckDB).
- Все значения — числа с точкой -> DOUBLE.
- Иначе -> VARCHAR / TEXT.
Что идёт не так:
| Случай | Что хочется | Что получится по умолчанию |
|---|---|---|
zip_code со значениями 01234, 02145 | VARCHAR (сохранить ведущие нули) | INTEGER (ноль потерян: 1234) |
date со значениями 2026-05-19 | DATE | VARCHAR |
is_active со значениями true, false | BOOLEAN | VARCHAR |
amount_usd со значениями 100.50 | NUMERIC(10,2) | DOUBLE (округление!) |
Исправление — задать column_types явно в YAML рядом с CSV. Файл seeds/_seeds.yml:
version: 2
seeds:
- name: country_codes
description: "Маппинг ISO кодов стран на регионы"
config:
column_types:
country_code: varchar(2)
country_name: varchar(100)
region: varchar(20)
gdp_per_capita_usd: numeric(12,2)
После этого dbt seed создаст таблицу с этими типами, а не угаданными.
Если CSV содержит DATE, TIMESTAMP, BOOLEAN или NUMERIC с фиксированной точностью — всегда указывайте column_types. Особенно для финансовых данных: DOUBLE плохо хранит деньги (округление 0.1 + 0.2 = 0.30000000000000004).
Конкретный пример: финансовые данные
Файл seeds/exchange_rates.csv:
date,from_currency,to_currency,rate
2026-05-01,USD,EUR,0.92
2026-05-01,USD,GBP,0.79
2026-05-01,USD,RUB,87.50
Если ничего не настроить — dbt создаст:
| Колонка | Тип после dbt seed |
|---|---|
| date | VARCHAR — а нужно DATE |
| from_currency | VARCHAR — ок |
| to_currency | VARCHAR — ок |
| rate | DOUBLE — а для финансов нужно NUMERIC(10,4) |
Правильный конфиг:
seeds:
- name: exchange_rates
config:
column_types:
date: date
from_currency: varchar(3)
to_currency: varchar(3)
rate: numeric(10,4)
columns:
- name: date
description: "Дата курса"
data_tests:
- not_null
- name: from_currency
data_tests:
- not_null
- name: rate
data_tests:
- not_null
Обратите внимание: в YAML можно сразу повесить тесты на колонки seed, точно так же как на модель.
quote_columns — экранирование имён колонок
Если CSV содержит имя колонки с пробелом, дефисом, или зарезервированное слово (from, select, order), dbt по умолчанию не оборачивает их в кавычки. SQL-запросы упадут.
Пример: CSV region_data.csv:
country,from,order
US,2020,1
GB,2021,2
Здесь from и order — зарезервированные слова. dbt сгенерит:
CREATE TABLE region_data (country VARCHAR, from VARCHAR, order VARCHAR);
-- Syntax error: "from" — reserved keyword
Решение:
seeds:
- name: region_data
config:
quote_columns: true
С quote_columns: true dbt оборачивает все имена в кавычки:
CREATE TABLE region_data ("country" VARCHAR, "from" VARCHAR, "order" VARCHAR);
Если включить quote_columns: true, то во всех downstream-моделях нужно тоже оборачивать имена в кавычки: SELECT "from" FROM .... Лучше переименовать колонки в CSV (например, from -> start_year), чем тащить кавычки через весь проект.
+schema и +database — куда складывать seed
По умолчанию seed создаётся в той же схеме, что и модели проекта (target schema из profiles.yml). Можно переопределить:
# dbt_project.yml
seeds:
jaffle_shop: # имя проекта из dbt_project.yml
+schema: reference # все seeds -> schema reference
finance: # подпапка seeds/finance/
+schema: finance_data # seeds/finance/*.csv -> schema finance_data
В DuckDB схема — это просто namespace. Таблица создастся как reference.country_codes. В ref('country_codes') ничего не меняется — dbt сам подставит правильный schema.
Префикс + в +schema означает «это конфиг, а не имя поддиректории» — это синтаксис dbt для отделения групповых конфигов от иерархии папок.
delimiter — нестандартный разделитель
Иногда CSV приходит с разделителем ; (Excel в Европе) или \t (TSV):
seeds:
- name: european_data
config:
delimiter: ";"
или прямо в dbt_project.yml:
seeds:
jaffle_shop:
european_data:
+delimiter: ";"
Дефолт — запятая. Если в CSV есть запятые внутри значений (например, "Tashkent, Uzbekistan"), они должны быть в двойных кавычках — это стандарт RFC 4180, dbt его поддерживает.
Полный пример: seeds/_seeds.yml
Хорошая практика — держать один YAML-файл рядом с CSV-файлами, описывающий все seeds в директории:
version: 2
seeds:
- name: country_codes
description: "ISO-3166 alpha-2 codes с маппингом на регионы и валюты"
config:
column_types:
country_code: varchar(2)
country_name: varchar(100)
region: varchar(20)
currency_code: varchar(3)
columns:
- name: country_code
description: "ISO-3166 alpha-2 code"
data_tests:
- unique
- not_null
- name: country_name
data_tests:
- not_null
- name: region
data_tests:
- accepted_values:
values: ['Americas', 'EMEA', 'APAC']
- name: exchange_rates
description: "Дневные курсы USD к основным валютам"
config:
column_types:
date: date
from_currency: varchar(3)
to_currency: varchar(3)
rate: numeric(10,4)
columns:
- name: rate
description: "Курс с точностью до 4 знаков"
data_tests:
- not_null
- dbt_utils.expression_is_true:
expression: "> 0"
Эти тесты запустятся при dbt test или dbt build — то есть seed валидируется на каждом ране CI.
Тесты на seed — это не магия
В dbt seed — это полноценная нода в DAG. На неё навешиваются:
data_tests(generic: not_null, unique, accepted_values, relationships) через YAML.- Singular tests (.sql файлы в tests/) могут ссылаться на seed через
ref('country_codes'). dbt_utilsтесты (equal_rowcount, expression_is_true) если установлен пакет.
Запуск:
dbt test --select country_codes # только тесты на этом seed
dbt build --select +my_model # включит seed + его тесты в цепочке
Что НЕ конфигурируется в seeds
В отличие от моделей, у seeds нет:
materialized— seed всегдаtableчерез DROP + CREATE + INSERT. Никаких view, incremental, ephemeral.partition_by/cluster_by— нет (warehouse-specific конфиги моделей).on_schema_change— нерелевантно, потому что каждый раз создаётся таблица заново.pre_hook/post_hook— теоретически работают, но в 99% случаев не нужны.incremental_strategy— seed это не incremental.
Если хочется управлять materialization — это не seed. Это inline-таблица в SQL-модели:
-- models/staging/_inline_lookup.sql
{{ config(materialized='table') }}
SELECT 'US' AS country, 'Americas' AS region UNION ALL
SELECT 'GB', 'EMEA' UNION ALL
SELECT 'JP', 'APAC'
Это антипаттерн для длинных списков (читаемость 0), но иногда уместно для 5-10 строк.
Попробуй сам
Создайте seeds/exchange_rates.csv:
date,from_currency,to_currency,rate
2026-05-01,USD,EUR,0.9205
2026-05-01,USD,GBP,0.7943
2026-05-02,USD,EUR,0.9220
2026-05-02,USD,GBP,0.7951
Запустите dbt seed без конфига. Посмотрите типы:
dbt show --inline "DESCRIBE exchange_rates"
Колонка date будет VARCHAR. Колонка rate — DOUBLE.
Теперь добавьте seeds/_seeds.yml с правильными column_types (date -> date, rate -> numeric(10,4)). Запустите dbt seed --full-refresh. Снова посмотрите типы.
Бонус: добавьте тест not_null на rate через YAML. Запустите dbt test --select exchange_rates. Что произойдёт, если поменять одну строку CSV на 2026-05-03,USD,EUR, (пустое значение в rate)?
Ключевые выводы
- column_types — самый важный конфиг. Без него dbt угадывает типы и ошибается на датах, decimal, boolean, ZIP-кодах с ведущими нулями.
- quote_columns: true включается, если в CSV есть зарезервированные слова или специальные символы в именах колонок.
- +schema и +database управляют, в какую схему/базу попадёт seed. Префикс
+отделяет конфиги от имён поддиректорий. - delimiter — для CSV с
;,\tили другим разделителем. - Конфигурация задаётся либо в dbt_project.yml (для дефолтов и групп), либо в YAML рядом с CSV (для индивидуальных настроек). YAML побеждает.
- На seed навешиваются тесты (not_null, unique, accepted_values) и descriptions точно так же, как на модель.
- Seed всегда materializes как
tableчерез DROP + CREATE + INSERT. Никаких view/incremental/ephemeral.