Calculate Adjusted EBITDA - Latest LTM and latest 2 full years
This template calculates adjusted EBITDA for latest LTM and last two full years
9 steps · August 13, 2026
No data is shared in this template. It contains only the recipe — column names and SQL logic. When you run it, your data is processed in your own browser and never leaves your machine.
What data it expects
QBO_ProfitAndLoss_Month.csv
section · VARCHARaccount · VARCHAR2024-01 · DOUBLE2024-02 · DOUBLE2024-03 · DOUBLE2024-04 · DOUBLE2024-05 · DOUBLE2024-06 · DOUBLE2024-07 · DOUBLE2024-08 · DOUBLE2024-09 · DOUBLE2024-10 · DOUBLE2024-11 · DOUBLE2024-12 · DOUBLE2025-01 · DOUBLE2025-02 · DOUBLE2025-03 · DOUBLE2025-04 · DOUBLE2025-05 · DOUBLE2025-06 · DOUBLE2025-07 · DOUBLE2025-08 · DOUBLE2025-09 · DOUBLE2025-10 · DOUBLE2025-11 · DOUBLE2025-12 · DOUBLE2026-01 · DOUBLE2026-02 · DOUBLE2026-03 · DOUBLE2026-04 · DOUBLE2026-05 · DOUBLE2026-06 · DOUBLE2026-07 · DOUBLETotal · DOUBLE
QBO_GeneralLedger.csv
account · VARCHARdate · VARCHARname · VARCHARmemo_description · VARCHARamount · DOUBLE
Connect QuickBooks Online or drop a CSV / Excel export with a similar layout — the AI adapts the workflow if your columns differ.
How it works — every step, readable
- 01Node 1 — Load QBO Monthly P&L
SELECT * FROM read_csv_auto('QBO_ProfitAndLoss_Month.csv', header=true) - 02Load QBO General Ledger Detail
SELECT * FROM read_csv_auto('QBO_GeneralLedger.csv', header=true) - 03Normalize Monthly P&L to Date-Based Linesfilters to the relevant rows · sorts the output
WITH unpvt AS ( SELECT section, account, period, raw_amount FROM input_1 UNPIVOT (raw_amount FOR period IN ( "2024-01", "2024-02", "2024-03", "2024-04", "2024-05", "2024-06", "2024-07", "2024-08", "2024-09", "2024-10", "2024-11", "2024-12", "2025-01", "2025-02", "2025-03", "2025-04", "2025-05", "2025-06", "2025-07", "2025-08", "2025-09", "2025-10", "2025-11", "2025-12", "2026-01", "2026-02", "2026-03", "2026-04", "2026-05", "2026-06", "2026-07" )) ) SELECT CAST(period || '-01' AS DATE) AS month_date, period AS "Month", TRIM(CAST(section AS VARCHAR)) AS section, TRIM(CAST(account AS VARCHAR)) AS account, ROUND(COALESCE(TRY_CAST(REPLACE(CAST(raw_amount AS VARCHAR), ',', '') AS DOUBLE), 0), 2) AS amount FROM unpvt WHERE account IS NOT NULL AND TRIM(CAST(account AS VARCHAR)) <> '' AND account NOT ILIKE '%total%' AND period <> 'Total' ORDER BY month_date, section, account - 04Node 2 — Monthly Summary Financials, Months as Columnsaggregates rows into summary totals · buckets values by condition · appends result sets (e.g. a TOTAL row)
WITH monthly AS ( SELECT month_date, "Month", SUM(CASE WHEN section ILIKE '%Income%' AND section NOT ILIKE '%Other%' THEN amount ELSE 0 END) AS sales, SUM(CASE WHEN section ILIKE '%Cost of Goods Sold%' THEN amount ELSE 0 END) AS cogs, SUM(CASE WHEN section ILIKE '%Expenses%' AND section NOT ILIKE '%Other%' THEN amount ELSE 0 END) AS opex, SUM(CASE WHEN section ILIKE '%Other Income%' THEN amount ELSE 0 END) AS other_income, SUM(CASE WHEN section ILIKE '%Other Expense%' THEN amount ELSE 0 END) AS other_expense, SUM(CASE WHEN account = 'Depreciation expenses' THEN amount ELSE 0 END) AS depreciation_amortization, SUM(CASE WHEN account = 'Interest expense' THEN amount ELSE 0 END) AS interest_expense, SUM(CASE WHEN LOWER(account) IN ('income tax expense', 'tax expense', 'provision for income taxes') OR LOWER(account) LIKE '%income tax%' THEN amount ELSE 0 END) AS income_tax_expense FROM input_1 GROUP BY month_date, "Month" ), lines AS ( SELECT month_date, "Month", 10 AS sort_order, 'Sales' AS "Line Item", sales AS amount FROM monthly UNION ALL SELECT month_date, "Month", 20, 'Cost of Goods Sold', cogs FROM monthly UNION ALL SELECT month_date, "Month", 30, 'Gross Profit', sales - cogs FROM monthly UNION ALL SELECT month_date, "Month", 40, 'Operating Expenses', opex FROM monthly UNION ALL SELECT month_date, "Month", 50, 'Operating Income', sales - cogs - opex FROM monthly UNION ALL SELECT month_date, "Month", 60, 'Other Income', other_income FROM monthly UNION ALL SELECT month_date, "Month", 70, 'Other Expense', other_expense FROM monthly UNION ALL SELECT month_date, "Month", 80, 'Net Income', sales - cogs - opex + other_income - other_expense FROM monthly UNION ALL SELECT month_date, "Month", 90, 'D&A Add-Back', depreciation_amortization FROM monthly UNION ALL SELECT month_date, "Month", 100, 'Interest Add-Back', interest_expense FROM monthly UNION ALL SELECT month_date, "Month", 110, 'Income Tax Add-Back', income_tax_expense FROM monthly UNION ALL SELECT month_date, "Month", 120, 'EBITDA', sales - cogs - opex + other_income - other_expense + depreciation_amortization + interest_expense + income_tax_expense FROM monthly ) SELECT "Line Item", ROUND(SUM(CASE WHEN "Month" = '2024-01' THEN amount ELSE 0 END), 2) AS "Jan 2024", ROUND(SUM(CASE WHEN "Month" = '2024-02' THEN amount ELSE 0 END), 2) AS "Feb 2024", ROUND(SUM(CASE WHEN "Month" = '2024-03' THEN amount ELSE 0 END), 2) AS "Mar 2024", ROUND(SUM(CASE WHEN "Month" = '2024-04' THEN amount ELSE 0 END), 2) AS "Apr 2024", ROUND(SUM(CASE WHEN "Month" = '2024-05' THEN amount ELSE 0 END), 2) AS "May 2024", ROUND(SUM(CASE WHEN "Month" = '2024-06' THEN amount ELSE 0 END), 2) AS "Jun 2024", ROUND(SUM(CASE WHEN "Month" = '2024-07' THEN amount ELSE 0 END), 2) AS "Jul 2024", ROUND(SUM(CASE WHEN "Month" = '2024-08' THEN amount ELSE 0 END), 2) AS "Aug 2024", ROUND(SUM(CASE WHEN "Month" = '2024-09' THEN amount ELSE 0 END), 2) AS "Sep 2024", ROUND(SUM(CASE WHEN "Month" = '2024-10' THEN amount ELSE 0 END), 2) AS "Oct 2024", ROUND(SUM(CASE WHEN "Month" = '2024-11' THEN amount ELSE 0 END), 2) AS "Nov 2024", ROUND(SUM(CASE WHEN "Month" = '2024-12' THEN amount ELSE 0 END), 2) AS "Dec 2024", ROUND(SUM(CASE WHEN "Month" = '2025-01' THEN amount ELSE 0 END), 2) AS "Jan 2025", ROUND(SUM(CASE WHEN "Month" = '2025-02' THEN amount ELSE 0 END), 2) AS "Feb 2025", ROUND(SUM(CASE WHEN "Month" = '2025-03' THEN amount ELSE 0 END), 2) AS "Mar 2025", ROUND(SUM(CASE WHEN "Month" = '2025-04' THEN amount ELSE 0 END), 2) AS "Apr 2025", ROUND(SUM(CASE WHEN "Month" = '2025-05' THEN amount ELSE 0 END), 2) AS "May 2025", ROUND(SUM(CASE WHEN "Month" = '2025-06' THEN amount ELSE 0 END), 2) AS "Jun 2025", ROUND(SUM(CASE WHEN "Month" = '2025-07' THEN amount ELSE 0 END), 2) AS "Jul 2025", ROUND(SUM(CASE WHEN "Month" = '2025-08' THEN amount ELSE 0 END), 2) AS "Aug 2025", ROUND(SUM(CASE WHEN "Month" = '2025-09' THEN amount ELSE 0 END), 2) AS "Sep 2025", ROUND(SUM(CASE WHEN "Month" = '2025-10' THEN amount ELSE 0 END), 2) AS "Oct 2025", ROUND(SUM(CASE WHEN "Month" = '2025-11' THEN amount ELSE 0 END), 2) AS "Nov 2025", ROUND(SUM(CASE WHEN "Month" = '2025-12' THEN amount ELSE 0 END), 2) AS "Dec 2025", ROUND(SUM(CASE WHEN "Month" = '2026-01' THEN amount ELSE 0 END), 2) AS "Jan 2026", ROUND(SUM(CASE WHEN "Month" = '2026-02' THEN amount ELSE 0 END), 2) AS "Feb 2026", ROUND(SUM(CASE WHEN "Month" = '2026-03' THEN amount ELSE 0 END), 2) AS "Mar 2026", ROUND(SUM(CASE WHEN "Month" = '2026-04' THEN amount ELSE 0 END), 2) AS "Apr 2026", ROUND(SUM(CASE WHEN "Month" = '2026-05' THEN amount ELSE 0 END), 2) AS "May 2026", ROUND(SUM(CASE WHEN "Month" = '2026-06' THEN amount ELSE 0 END), 2) AS "Jun 2026", ROUND(SUM(CASE WHEN "Month" = '2026-07' THEN amount ELSE 0 END), 2) AS "Jul 2026", ROUND(SUM(amount), 2) AS "Total" FROM lines GROUP BY sort_order, "Line Item" ORDER BY sort_order - 05Node 3 — Add FY 2024, FY 2025, YTD 2026, and Latest LTM Columnsaggregates rows into summary totals · buckets values by condition · appends result sets (e.g. a TOTAL row)
WITH monthly AS ( SELECT month_date, "Month", SUM(CASE WHEN section ILIKE '%Income%' AND section NOT ILIKE '%Other%' THEN amount ELSE 0 END) AS sales, SUM(CASE WHEN section ILIKE '%Cost of Goods Sold%' THEN amount ELSE 0 END) AS cogs, SUM(CASE WHEN section ILIKE '%Expenses%' AND section NOT ILIKE '%Other%' THEN amount ELSE 0 END) AS opex, SUM(CASE WHEN section ILIKE '%Other Income%' THEN amount ELSE 0 END) AS other_income, SUM(CASE WHEN section ILIKE '%Other Expense%' THEN amount ELSE 0 END) AS other_expense, SUM(CASE WHEN account = 'Depreciation expenses' THEN amount ELSE 0 END) AS depreciation_amortization, SUM(CASE WHEN account = 'Interest expense' THEN amount ELSE 0 END) AS interest_expense, SUM(CASE WHEN LOWER(account) IN ('income tax expense', 'tax expense', 'provision for income taxes') OR LOWER(account) LIKE '%income tax%' THEN amount ELSE 0 END) AS income_tax_expense FROM input_1 GROUP BY month_date, "Month" ), latest AS ( SELECT MAX(month_date) AS latest_month FROM monthly ), lines AS ( SELECT month_date, 10 AS sort_order, 'Sales' AS "Line Item", sales AS amount FROM monthly UNION ALL SELECT month_date, 20, 'Cost of Goods Sold', cogs FROM monthly UNION ALL SELECT month_date, 30, 'Gross Profit', sales - cogs FROM monthly UNION ALL SELECT month_date, 40, 'Operating Expenses', opex FROM monthly UNION ALL SELECT month_date, 50, 'Operating Income', sales - cogs - opex FROM monthly UNION ALL SELECT month_date, 60, 'Other Income', other_income FROM monthly UNION ALL SELECT month_date, 70, 'Other Expense', other_expense FROM monthly UNION ALL SELECT month_date, 80, 'Net Income', sales - cogs - opex + other_income - other_expense FROM monthly UNION ALL SELECT month_date, 90, 'D&A Add-Back', depreciation_amortization FROM monthly UNION ALL SELECT month_date, 100, 'Interest Add-Back', interest_expense FROM monthly UNION ALL SELECT month_date, 110, 'Income Tax Add-Back', income_tax_expense FROM monthly UNION ALL SELECT month_date, 120, 'EBITDA', sales - cogs - opex + other_income - other_expense + depreciation_amortization + interest_expense + income_tax_expense FROM monthly ) SELECT "Line Item", ROUND(SUM(CASE WHEN month_date BETWEEN DATE '2024-01-01' AND DATE '2024-12-01' THEN amount ELSE 0 END), 2) AS "FY 2024", ROUND(SUM(CASE WHEN month_date BETWEEN DATE '2025-01-01' AND DATE '2025-12-01' THEN amount ELSE 0 END), 2) AS "FY 2025", ROUND(SUM(CASE WHEN month_date BETWEEN DATE '2026-01-01' AND (SELECT latest_month FROM latest) THEN amount ELSE 0 END), 2) AS "YTD 2026", ROUND(SUM(CASE WHEN month_date BETWEEN ((SELECT latest_month FROM latest) - INTERVAL 11 MONTH) AND (SELECT latest_month FROM latest) THEN amount ELSE 0 END), 2) AS "Latest LTM" FROM lines GROUP BY sort_order, "Line Item" ORDER BY sort_order - 06Node 4 — EBITDA Bridge from Net Income with Add-Backsfilters to the relevant rows · sorts the output
SELECT CASE "Line Item" WHEN 'Sales' THEN 10 WHEN 'Net Income' THEN 20 WHEN 'D&A Add-Back' THEN 30 WHEN 'Interest Add-Back' THEN 40 WHEN 'Income Tax Add-Back' THEN 50 WHEN 'EBITDA' THEN 60 ELSE 99 END AS sort_order, "Line Item", "FY 2024", "FY 2025", "YTD 2026", "Latest LTM" FROM input_1 WHERE "Line Item" IN ('Sales', 'Net Income', 'D&A Add-Back', 'Interest Add-Back', 'Income Tax Add-Back', 'EBITDA') ORDER BY sort_order - 07Node 5 — Annual QoE Base: Latest Two Full Years and LTM Onlysorts the output
SELECT "Line Item", ROUND("FY 2024", 2) AS "2024", ROUND("FY 2025", 2) AS "2025", ROUND("Latest LTM", 2) AS "LTM" FROM input_1 ORDER BY sort_order - 08Node 6 — GL Detail One-Off Identification and Add-Back Candidatescombines data from multiple inputs · aggregates rows into summary totals · buckets values by condition
WITH pl_months AS ( SELECT DISTINCT month_date FROM input_1 ), gl_clean AS ( SELECT TRY_CAST("date" AS DATE) AS txn_date, DATE_TRUNC('month', TRY_CAST("date" AS DATE))::DATE AS month_date, TRIM(CAST(account AS VARCHAR)) AS account, TRIM(COALESCE(CAST(name AS VARCHAR), '')) AS name, TRIM(COALESCE(CAST(memo_description AS VARCHAR), '')) AS memo_description, COALESCE(TRY_CAST(REPLACE(CAST(amount AS VARCHAR), ',', '') AS DOUBLE), 0) AS amount, LOWER(TRIM(COALESCE(CAST(account AS VARCHAR), '') || ' ' || COALESCE(CAST(name AS VARCHAR), '') || ' ' || COALESCE(CAST(memo_description AS VARCHAR), ''))) AS search_text FROM input_2 WHERE TRY_CAST("date" AS DATE) IS NOT NULL ), joined_to_pl_periods AS ( SELECT g.* FROM gl_clean g INNER JOIN pl_months p ON g.month_date = p.month_date ), flagged AS ( SELECT txn_date, month_date, account, name, memo_description, amount, ABS(amount) AS addback_amount, CASE WHEN regexp_matches(search_text, 'settlement|lawsuit|litigation|legal claim|judgment') THEN 'Legal / settlement / litigation' WHEN regexp_matches(search_text, 'acquisition|transaction|due diligence|qofe|quality of earnings|deal cost') THEN 'Transaction / acquisition-related cost' WHEN regexp_matches(search_text, 'restructuring|severance|layoff|termination') THEN 'Restructuring / severance' WHEN regexp_matches(search_text, 'relocation|moving|move |office move|facility move') THEN 'Relocation / facility move' WHEN regexp_matches(search_text, 'write.?off|impairment|obsolete|disposal') THEN 'Write-off / impairment / disposal' WHEN regexp_matches(search_text, 'penalty|fine|late fee') THEN 'Penalty / fine / late fee' WHEN regexp_matches(search_text, 'one.?time|non.?recurring|nonrecurring|extraordinary|unusual') THEN 'Explicit one-time / non-recurring' WHEN account IN ('Legal & professional services', 'Repairs & maintenance', 'Other operating expenses') AND ABS(amount) >= 5000 THEN 'Large discretionary or unusual expense for review' ELSE NULL END AS "Add-Back Category" FROM joined_to_pl_periods WHERE account NOT IN ('Depreciation expenses', 'Interest expense') ), reviewed AS ( SELECT * FROM flagged WHERE "Add-Back Category" IS NOT NULL AND addback_amount > 0 ) SELECT "Add-Back Category", COUNT(*) AS "Transaction Count", ROUND(MAX(addback_amount), 2) AS "Largest Transaction", STRING_AGG(DISTINCT account, ' | ') AS "Accounts Flagged", STRING_AGG(DISTINCT LEFT(NULLIF(name || ' - ' || memo_description, ' - '), 120), ' | ') AS "Example Vendors / Memos", ROUND(SUM(CASE WHEN month_date BETWEEN DATE '2024-01-01' AND DATE '2024-12-01' THEN addback_amount ELSE 0 END), 2) AS "2024", ROUND(SUM(CASE WHEN month_date BETWEEN DATE '2025-01-01' AND DATE '2025-12-01' THEN addback_amount ELSE 0 END), 2) AS "2025", ROUND(SUM(CASE WHEN month_date BETWEEN DATE '2026-01-01' AND (SELECT MAX(month_date) FROM pl_months) THEN addback_amount ELSE 0 END), 2) AS "YTD 2026", ROUND(SUM(CASE WHEN month_date BETWEEN ((SELECT MAX(month_date) FROM pl_months) - INTERVAL 11 MONTH) AND (SELECT MAX(month_date) FROM pl_months) THEN addback_amount ELSE 0 END), 2) AS "LTM" FROM reviewed GROUP BY "Add-Back Category" ORDER BY "LTM" DESC, "2025" DESC, "2024" DESC - 09Node 7 — Final QoE Table: Sales, EBITDA, Add-Backs, Adjusted EBITDAcombines data from multiple inputs · aggregates rows into summary totals · buckets values by condition
WITH base AS ( SELECT MAX(CASE WHEN "Line Item" = 'Sales' THEN TRY_CAST("2024" AS DOUBLE) END) AS sales_2024, MAX(CASE WHEN "Line Item" = 'Sales' THEN TRY_CAST("2025" AS DOUBLE) END) AS sales_2025, MAX(CASE WHEN "Line Item" = 'Sales' THEN TRY_CAST("LTM" AS DOUBLE) END) AS sales_ltm, MAX(CASE WHEN "Line Item" = 'EBITDA' THEN TRY_CAST("2024" AS DOUBLE) END) AS ebitda_2024, MAX(CASE WHEN "Line Item" = 'EBITDA' THEN TRY_CAST("2025" AS DOUBLE) END) AS ebitda_2025, MAX(CASE WHEN "Line Item" = 'EBITDA' THEN TRY_CAST("LTM" AS DOUBLE) END) AS ebitda_ltm FROM input_1 ), input2_json AS ( SELECT to_json(i2) AS j FROM input_2 i2 ), input2_normalized AS ( SELECT json_extract_string(j, '$."Add-Back Category"') AS addback_category, TRY_CAST(json_extract_string(j, '$."Transaction Count"') AS BIGINT) AS transaction_count_summary, TRY_CAST(json_extract_string(j, '$."Largest Transaction"') AS DOUBLE) AS largest_transaction_summary, json_extract_string(j, '$."Accounts Flagged"') AS accounts_flagged_summary, json_extract_string(j, '$."Example Vendors / Memos"') AS examples_summary, TRY_CAST(json_extract_string(j, '$."2024"') AS DOUBLE) AS summary_2024, TRY_CAST(json_extract_string(j, '$."2025"') AS DOUBLE) AS summary_2025, TRY_CAST(json_extract_string(j, '$."LTM"') AS DOUBLE) AS summary_ltm, TRY_CAST(json_extract_string(j, '$."Transaction Date"') AS DATE) AS transaction_date, TRY_CAST(json_extract_string(j, '$."Add-Back Amount"') AS DOUBLE) AS addback_amount, COALESCE( json_extract_string(j, '$."account"'), json_extract_string(j, '$."Account"') ) AS account_text, NULLIF( CONCAT_WS( ' / ', COALESCE( json_extract_string(j, '$."name"'), json_extract_string(j, '$."Name"') ), COALESCE( json_extract_string(j, '$."memo_description"'), json_extract_string(j, '$."Memo Description"'), json_extract_string(j, '$."Memo"') ) ), '' ) AS example_text FROM input2_json ), input2_with_max_date AS ( SELECT *, MAX(transaction_date) OVER () AS max_transaction_date FROM input2_normalized WHERE addback_category IS NOT NULL ), addback_detail AS ( SELECT addback_category AS "Add-Back Category", COALESCE( MAX(transaction_count_summary), COUNT(*) FILTER (WHERE addback_amount IS NOT NULL), 0 ) AS "Transaction Count", COALESCE( MAX(largest_transaction_summary), MAX(ABS(addback_amount)), 0 ) AS "Largest Transaction", COALESCE( MAX(accounts_flagged_summary), STRING_AGG(DISTINCT account_text, ', ' ORDER BY account_text) FILTER (WHERE account_text IS NOT NULL AND account_text <> '') ) AS "Accounts Flagged", COALESCE( MAX(examples_summary), STRING_AGG(DISTINCT example_text, ', ' ORDER BY example_text) FILTER (WHERE example_text IS NOT NULL AND example_text <> '') ) AS "Example Vendors / Memos", COALESCE( SUM(summary_2024), SUM(CASE WHEN EXTRACT(YEAR FROM transaction_date) = 2024 THEN addback_amount ELSE 0 END), 0 ) AS addback_2024, COALESCE( SUM(summary_2025), SUM(CASE WHEN EXTRACT(YEAR FROM transaction_date) = 2025 THEN addback_amount ELSE 0 END), 0 ) AS addback_2025, COALESCE( SUM(summary_ltm), SUM( CASE WHEN transaction_date > max_transaction_date - INTERVAL 12 MONTH AND transaction_date <= max_transaction_date THEN addback_amount ELSE 0 END ), 0 ) AS addback_ltm FROM input2_with_max_date GROUP BY addback_category ), addback_totals AS ( SELECT COALESCE(SUM(addback_2024), 0) AS addbacks_2024, COALESCE(SUM(addback_2025), 0) AS addbacks_2025, COALESCE(SUM(addback_ltm), 0) AS addbacks_ltm FROM addback_detail ), report_rows AS ( SELECT 10 AS sort_order, 'Sales' AS "Line Item", sales_2024 AS "2024", sales_2025 AS "2025", sales_ltm AS "LTM", NULL::BIGINT AS "Transaction Count", NULL::DOUBLE AS "Largest Transaction", NULL::VARCHAR AS "Accounts Flagged", NULL::VARCHAR AS "Example Vendors / Memos" FROM base UNION ALL SELECT 20, 'EBITDA', ebitda_2024, ebitda_2025, ebitda_ltm, NULL::BIGINT, NULL::DOUBLE, NULL::VARCHAR, NULL::VARCHAR FROM base UNION ALL SELECT 30 + ROW_NUMBER() OVER ( ORDER BY addback_ltm DESC, addback_2025 DESC, addback_2024 DESC ) AS sort_order, 'Add-Back: ' || "Add-Back Category" AS "Line Item", addback_2024 AS "2024", addback_2025 AS "2025", addback_ltm AS "LTM", "Transaction Count", "Largest Transaction", "Accounts Flagged", "Example Vendors / Memos" FROM addback_detail UNION ALL SELECT 80, 'Total Add-Backs', addbacks_2024, addbacks_2025, addbacks_ltm, NULL::BIGINT, NULL::DOUBLE, NULL::VARCHAR, NULL::VARCHAR FROM addback_totals UNION ALL SELECT 90, 'Adjusted EBITDA', ebitda_2024 + addbacks_2024, ebitda_2025 + addbacks_2025, ebitda_ltm + addbacks_ltm, NULL::BIGINT, NULL::DOUBLE, NULL::VARCHAR, NULL::VARCHAR FROM base CROSS JOIN addback_totals UNION ALL SELECT 100, 'Adj. EBITDA % of Sales', CASE WHEN sales_2024 <> 0 THEN (ebitda_2024 + addbacks_2024) / sales_2024 * 100 ELSE NULL END, CASE WHEN sales_2025 <> 0 THEN (ebitda_2025 + addbacks_2025) / sales_2025 * 100 ELSE NULL END, CASE WHEN sales_ltm <> 0 THEN (ebitda_ltm + addbacks_ltm) / sales_ltm * 100 ELSE NULL END, NULL::BIGINT, NULL::DOUBLE, NULL::VARCHAR, NULL::VARCHAR FROM base CROSS JOIN addback_totals ) SELECT "Line Item", ROUND("2024", 2) AS "2024", ROUND("2025", 2) AS "2025", ROUND("LTM", 2) AS "LTM", "Transaction Count", ROUND("Largest Transaction", 2) AS "Largest Transaction", "Accounts Flagged", "Example Vendors / Memos" FROM report_rows ORDER BY sort_order
Run this on your books
Free to try — no sign-up, no card. The workflow runs in your browser; your data never leaves your machine.
Make it your own →