PnL Rollup

Recursively aggregates PnL values across the GL account hierarchy for reporting.

Purpose

Produce a reporting-ready PnL dataset where amounts are available at all GL hierarchy levels, not just leaf accounts. This model centralizes hierarchical aggregation logic so downstream consumers do not need to reimplement it.

Business Logic

  • Start from atomic PnL entries at the lowest GL account level
  • Use the GL account hierarchy to identify parent–child relationships
  • Recursively propagate amounts from child accounts to all parent accounts
  • Aggregate amounts per:
    • Date
    • GL account (leaf and parent)
    • Value Type

Output Contract

Definitions

ColumnDescription
dateDate represented as YYYY-MM-DD. Links to Dates semantic contract
gl_idGL Account identifier. Links to GL Accounts semantic contract
gl_accountGL Account name at any hierarchy level. Links to GL Accounts semantic contract
value_type_idValue Type identifier. Links to Value Type semantic contract
typeValue Type name. Links to Value Type semantic contract
amountAggregated amount including all child accounts

Sample & Implementation

PnL Raw Data with aggregated values for each parent GL
dategl_idgl_accountvalue_type_idvalue_typeamount
2025-01-011000revenue1actuals13744178
2025-01-011010subscriptions1actuals13743233
2025-01-011020services1actuals451
2025-01-011030others1actuals494
2025-01-012000cogs1actuals584704
2025-01-012010payment_fees1actuals584236
2025-01-012020other_costs1actuals468
2025-01-014000commercial_costs1actuals222010
2025-01-014010sales1actuals117750
2025-01-014011sales_staff1actuals107188
{{config(materialized='view')}}

WITH RECURSIVE pnl as (
    select * from {{ref('pnl')}}
),

gl_accounts as (
    select * from {{ref('gl_accounts')}}
),

pnl_rollup as (
    select
        date,
        gl_account_id,
        value_type_id,
        amount,
        0 as level
    from pnl

    union all

    select
        pr.date,
        ga.parent_gl as gl_account_id,
        pr.value_type_id,
        pr.amount,
        pr.level + 1
    from pnl_rollup pr
    join gl_accounts ga on ga.id = pr.gl_account_id
    join gl_accounts parent_ga on parent_ga.id = ga.parent_gl
    where ga.parent_gl is not null
)

select
    p.date,
    ga.id as gl_id,
    ga.name as gl_account,
    pnlr.value_type_id,
    vt.name as value_type,
    SUM(pnlr.amount)::double as amount
from pnl_rollup pnlr
join dates p ON p.date = pnlr.date
join gl_accounts ga ON ga.id = pnlr.gl_account_id
join value_types vt ON vt.id = pnlr.value_type_id
group by p.date, ga.id, ga.name, pnlr.value_type_id, vt.name
order by value_type_id, p.date, gl_id

Dependencies

On this page

Star us on GitHub

If you enjoy this content and find it useful, give us a star on GitHub to show your support and stay updated with our latest improvements.