In de praktijk bouw je deze lagen met dbt. Je schrijft SELECT-statements, dbt maakt er tabellen of views van, en met ref() verwijs je van het ene model naar het andere. Daaruit leidt dbt de bouwvolgorde af.
Een marketingmart is meestal al geaggregeerd. Niet elke gebeurtenis, maar één rij per dag per kanaal. Dat scheelt twee dingen: je dashboard laadt snel, en je scant in BigQuery megabytes in plaats van gigabytes, want je betaalt per gescande byte.
-- models/marts/marketing/mart_channel_performance.sql
{{ config(materialized='table', partition_by={'field': 'date_day', 'data_type': 'date'}) }}
with sessions as (
select date_day, channel, count(distinct session_id) as sessions
from {{ ref('int_ga4_sessions') }}
group by 1, 2
),
orders as (
select date_day, channel, count(*) as orders, sum(revenue_ex_vat) as revenue
from {{ ref('int_orders_attributed') }}
where is_test_order = false
group by 1, 2
),
spend as (
select date_day, channel, sum(cost) as cost
from {{ ref('stg_ads__daily_cost') }}
group by 1, 2
)
select
sessions.date_day,
sessions.channel,
sessions.sessions,
coalesce(orders.orders, 0) as orders,
coalesce(orders.revenue, 0) as revenue,
coalesce(spend.cost, 0) as cost
from sessions
left join orders using (date_day, channel)
left join spend using (date_day, channel)
Let op wat hier al beslist is: testorders zijn eruit, omzet is exclusief btw, en de toerekening aan een kanaal gebeurt in het model eronder. Wie dit dashboard opent, kan die keuzes niet per ongeluk anders maken.