Portfolio laboratory

Python + SQL projects

End-to-end analytical workflows that join, validate, model and communicate business data.

All datasets and commercial scenarios on this page are synthetic and created for portfolio demonstration.

Choose a case.

Each case includes the business question, source structure, working method, selected code or decision logic, measured result, recommendation and limitations.

Major synthetic case studyPython

FP&A planning & variance control tower

Which actions protect EBITDA when revenue, cost and commitments move together?

A governed monthly P&L pipeline, material variance queue and three-scenario reforecast that connects ledger controls to management action and operating cash.

312-line Python + SQL workflow · data controls · P&L model · variance queue · scenarios

£11.0m
base EBITDA
+£946k
recovery upside
£2.0m
downside exposure
View full case study
Synthetic case studyPython

Executive sales KPI pipeline

Can leadership trust the number before discussing the trend?

A small analytical pipeline that removes duplicate orders, standardises channels, filters business-valid revenue and exposes an auditable customer-level mart.

47
duplicates removed
3,171
valid completed orders
£346k
governed revenue
View full case study
Synthetic case studySQL

Customer 360 & retention queue

Which valuable customers are becoming quiet?

A relational customer mart and RFM-style prioritisation layer that connects value, frequency and recency to an actionable outreach queue.

134
high-value at-risk customers
40.9%
revenue from top 20%
5
joined source fields
View full case study
Case 01
Major synthetic case study3,888 ledger rows · 18 monthsPython · SQLite · pandas · Scenario modelling

FP&A planning & variance control tower

Which actions protect EBITDA when revenue, cost and commitments move together?

A governed monthly P&L pipeline, material variance queue and three-scenario reforecast that connects ledger controls to management action and operating cash.

£11.0m
base EBITDA
+£946k
recovery upside
£2.0m
downside exposure

Business context

A four-unit infrastructure group has an 18-month ledger, budget, open commitments and uneven commercial performance. Leadership needs a reforecast that reconciles to finance data and makes the action behind each variance visible.

Questions tested

  1. Which business units and accounts explain the material EBITDA variance?
  2. How much of the apparent result remains exposed to committed cost?
  3. What does a management recovery case protect, and what trigger defines the downside?

Working method

From raw information to a decision.

  1. 01

    Validated 3,888 cost-centre/account/month records for completeness, uniqueness and unsigned ledger values.

  2. 02

    Loaded a governed ledger to SQLite and applied one signed P&L definition for revenue, direct cost, operating expense and EBITDA.

  3. 03

    Built business-unit/month views and a materiality-ranked variance action queue with commitments included.

  4. 04

    Modelled base, management-recovery and downside scenarios using explicit revenue, inflation, discretionary-cost and cash-conversion assumptions.

  5. 05

    Exported an executive summary, monthly P&L and the complete action queue so each headline can be traced back to source rows.

Dataset

Visible grain, fields and sample.

month / business_unitReporting period and management view
cost_centre / functionAccountability and operating owner
account / account_typeRevenue, direct cost or operating expense
budget_gbp / actual_gbpBaseline and reported financial value
committed_gbpApproved cost not yet fully reflected in actuals
headcount_fteIllustrative operating driver
MonthUnitCentreAccountTypeBudgetActual
Jan 2025North InfrastructureCC-101Project revenueRevenue£63,294£67,998
Jan 2025North InfrastructureCC-101Recurring serviceRevenue£26,468£27,553
Jan 2025North InfrastructureCC-101Product revenueRevenue£22,441£23,688

Preview shows three records; the complete synthetic dataset is available above.

Selected workingPython + SQLite
WITH signed_ledger AS (
  SELECT month, business_unit, cost_centre, account_type,
    CASE WHEN account_type = 'Revenue'
      THEN actual_gbp ELSE -actual_gbp END AS signed_actual,
    CASE WHEN account_type = 'Revenue'
      THEN budget_gbp ELSE -budget_gbp END AS signed_budget,
    CASE WHEN account_type = 'Revenue'
      THEN 0 ELSE -committed_gbp END AS signed_commitment
  FROM ledger
)
SELECT month, business_unit,
  SUM(signed_actual) AS actual_ebitda_gbp,
  SUM(signed_actual - signed_budget) AS variance_gbp,
  SUM(signed_actual + signed_commitment) AS exposed_ebitda_gbp
FROM signed_ledger
GROUP BY month, business_unit;

Result

Management recovery£11.96m EBITDA
Base£11.02m EBITDA
Downside£9.03m EBITDA
  • The controlled ledger produced £11.02m of base EBITDA across 18 months with no duplicate keys or missing required values.
  • The material queue contained £2.27m of adverse variance; the five largest items represented 16.1% of that exposure.
  • The management recovery scenario improved EBITDA by £945,641, while the explicit downside reduced it by £1.99m.
  • In the latest month, South Infrastructure was £47,971 below budget EBITDA and remained the clearest management intervention point.

Recommendation

Approve the targeted recovery case: protect South Infrastructure revenue, challenge direct-material and travel exposure, and validate discretionary reductions by owner. Retain the downside as a trigger plan rather than blending it into one point forecast.

Limits & next evidence

The synthetic model excludes balance-sheet timing, tax, financing, project-level revenue recognition and causal driver forecasts. A live reforecast would require validated operational drivers and finance sign-off on accounting treatment.

Case 02
Synthetic case study600 customers · 3,547 raw ordersPython · SQLite · pandas · Data quality

Executive sales KPI pipeline

Can leadership trust the number before discussing the trend?

A small analytical pipeline that removes duplicate orders, standardises channels, filters business-valid revenue and exposes an auditable customer-level mart.

47
duplicates removed
3,171
valid completed orders
£346k
governed revenue

Business context

Leadership receives different revenue totals from sales and finance. This project demonstrates the governance layer that should precede any executive dashboard.

Questions tested

  1. Which records fail uniqueness and completeness rules?
  2. What is the agreed definition of reportable revenue?
  3. Can a monthly KPI table be reproduced from the same transformation every time?

Working method

From raw information to a decision.

  1. 01

    Profiled duplicates, missing channel values and status distribution before changing data.

  2. 02

    Removed 47 duplicate order IDs, standardised blank channels and retained completed orders only.

  3. 03

    Loaded controlled tables to SQLite and calculated monthly KPIs from one query.

  4. 04

    Kept the data-quality counts beside the commercial output for auditability.

Dataset

Visible grain, fields and sample.

order_idExpected unique order key
customer_idJoin key to customer master
order_value_gbpOrder value before validity filter
statusCompleted, returned or cancelled
channelWeb, marketplace, assisted or unknown
OrderCustomerDateValueStatusChannel
O-00001C-030931 Jan 2025£42.59CompletedWeb
O-00002C-048611 Dec 2025£88.16CompletedWeb
O-00003C-052008 Mar 2026£90.94CompletedSales-assisted

Preview shows three records; the complete synthetic dataset is available above.

Selected workingPython + SQL
orders = raw_orders.drop_duplicates("order_id").copy()
orders["channel"] = orders["channel"].fillna("Unknown")
orders = orders.loc[orders["status"].eq("Completed")]

monthly_kpis = pd.read_sql_query("""
  SELECT substr(order_date, 1, 7) AS month,
         COUNT(*) AS completed_orders,
         ROUND(SUM(order_value_gbp), 2) AS revenue_gbp,
         ROUND(AVG(order_value_gbp), 2) AS aov_gbp
  FROM orders
  GROUP BY 1 ORDER BY 1
""", database)

Result

  • The raw extract contained 3,547 rows and 47 duplicate order IDs.
  • After deduplication and status filtering, 3,171 completed orders remained.
  • The governed dataset reconciled to £345,737 of completed revenue.

Recommendation

Publish KPI definitions with the pipeline, assign an owner to each exception rule, and block dashboard refresh when uniqueness or reconciliation checks fail.

Limits & next evidence

This local example does not model incremental loads, slowly changing dimensions, refunds posted in later periods or role-based access. Those are required for production governance.

Case 03
Synthetic case study600 customers · relational order historySQL · Python · RFM · Segmentation

Customer 360 & retention queue

Which valuable customers are becoming quiet?

A relational customer mart and RFM-style prioritisation layer that connects value, frequency and recency to an actionable outreach queue.

134
high-value at-risk customers
40.9%
revenue from top 20%
5
joined source fields

Business context

Account teams need to distinguish a naturally infrequent buyer from a valuable customer whose engagement has changed. The case builds a relational customer view and a ranked re-engagement queue.

Questions tested

  1. How much value, frequency and recency belongs to each customer?
  2. How concentrated is revenue among the top-value cohort?
  3. Which previously active customers have now been quiet for more than 120 days?

Working method

From raw information to a decision.

  1. 01

    Joined the 600-row customer master to cleaned completed orders in SQLite.

  2. 02

    Calculated lifetime value, order frequency, AOV and last-order date at customer grain.

  3. 03

    Created quartile value bands and a transparent recency/frequency rule.

  4. 04

    Ranked qualified customers by relative value and recency for account-team action.

Dataset

Visible grain, fields and sample.

customer_idStable relational key
segmentConsumer, small business or enterprise
marketing_sourceRecorded acquisition origin
order_frequencyCount of completed orders
lifetime_value_gbpCompleted-order revenue
recency_daysDays since last order at snapshot
CustomerSigned upRegionSegmentSource
C-000116 Oct 2024LondonSmall BusinessSocial
C-000230 Sep 2024MidlandsConsumerReferral
C-000323 May 2024NorthConsumerReferral

Preview shows three records; the complete synthetic dataset is available above.

Selected workingSQL + Python
SELECT c.customer_id, c.region, c.segment, c.marketing_source,
       COUNT(o.order_id) AS order_frequency,
       ROUND(COALESCE(SUM(o.order_value_gbp), 0), 2) AS lifetime_value_gbp,
       MAX(o.order_date) AS last_order_date
FROM customers c
LEFT JOIN orders o ON o.customer_id = c.customer_id
GROUP BY c.customer_id, c.region, c.segment, c.marketing_source;

retention_queue = customer_360[
    (customer_360.order_frequency >= 4)
    & (customer_360.recency_days > 120)
]

Result

  • The top 20% of customers contributed 40.9% of completed revenue.
  • The rule identified 134 high-value at-risk customers for evidence-based re-engagement.
  • Consumer was the highest-revenue segment because it dominated the synthetic customer mix.

Recommendation

Give account teams the ranked queue with last purchase, segment and value context; record contact outcome so future prioritisation can learn from actual reactivation.

Limits & next evidence

The sample has no cost-to-serve, consent, contact history or margin. Production prioritisation should optimise incremental value and comply with marketing permissions.