Truck fleet profitability report with Power BI

Case study · Power BI

Truck fleet profitability: which truck actually earns

Three systems that name the same truck differently → one star-schema model → four pages that show not only which truck is loss-making, but why.

Power Query
Unpivot
Merge Queries
Star schema
DAX
Conditional formatting
Power BI
2.4 %
fleet margin over 8 months
6 of 24
trucks ran at a loss
3 → 1
systems merged into one model
2,804
rows of data
Context

The task

A carrier running a fleet of 24 trucks sees the overall result: how much was earned, how much was spent. But when the margin drops to a few percent, the overall number stops helping — you need to know which truck is eating it, and why. The problem is that the answer is scattered across three systems that do not talk to each other: the TMS knows the trips, the fuel-card provider knows the refuels, accounting knows the costs. And each one names the same truck in its own way.

Before

  • Three systems that write the same truck differently: V-104, LT104, Volvo FH 104 (ABC104)
  • The overall fleet margin is visible, but not the individual truck
  • Fuel costs live separately from everything else — and that is 47 % of the whole cost basket
  • A loss-making truck can be spotted, but not explained: rate? empty running? fuel? repairs?

Solution

  • A hand-built truck reference table that joins all three systems
  • A star-schema model with a calendar — costs are monthly, so every filter works at month level
  • 18 DAX measures: from margin to fuel overspend in euros against the norm
  • Four pages: fleet → trucks → routes → methodology
How it works

The data path — from files to model

CSV
3 systems
TMS · fuel cards · accounting
→
PQ
Power Query
cleaning · Unpivot · Merge
→
⭐
Star schema
facts + 3 dimensions + calendar
→
DAX
18 measures
margin · €/km · l/100 · overspend
→
▦
Report
4 pages with filters
Result

The report

Fleet margin overview · January–August 2026 · demonstration data
Proof

The real thing in Power BI

The same report and model in the actual Power BI Desktop environment — with the ribbon, the Visualizations and Data panes, and the relationships between tables.

Truck margin report main page in the Power BI Desktop environment
Fleet — KPI metrics, margin by truck and cost structure
Truck metrics table with loss-making rows highlighted
Trucks — a metrics table with conditional formatting, where the cell background marks the cause of the problem
Route and customer analysis: rate per loaded kilometre
Routes — rate per loaded kilometre, a customer matrix and a trip scatter chart
Under the hood

How the model is built

The folder structure is set up so that each month you only drop in the new files and press Refresh — the model re-lays itself out.

📁 Carrier
├── 📁 00_originals ← untouched copy of the sources
├── 📁 01_data
│ ├── 📄 trucks.csv 24 rows
│ ├── 📄 trips.csv 1,744 rows
│ ├── 📄 fuel.csv 868 rows
│ └── 📄 costs.csv 192 rows
├── 📁 02_report
│ └── 📊 carrier-report.pbix
├── 📁 03_export
└── 📁 04_documentation
New monthly files → 01_data → Refresh → the model updates
1
Import Text/CSV · UTF-8 (65001), Semicolon delimiter — Lithuanian characters and comma decimals
2
Data Type Detection = Do not detect · so Power Query does not create a Changed Type with an English locale and corrupt the decimals
3
Replace Values · V 104 → V-104, dots in dates → dashes. Clean text first, types last — in separate steps
4
Change Type Using Locale · lt-LT for numbers, English (UK) for dates like 14/03/2026 — the locale matches how the value is written in the file
5
Merge Queries (Left Outer) × 2 · Fuel and Costs joined to the truck reference table, TMS_code expanded
6
Unpivot Other Columns · not Unpivot Columns: a ninth cost type that appears later is pulled in automatically. 192 → 1,536 rows
7
Validation queries · filter [TMS_code] = null, Enable load off. A truck with no match in the reference table lands here instead of hiding in the total
8
Calendar via ADDCOLUMNS(CALENDAR(…)) · marked as a date table, Month sorted by MonthNo
9
Six relationships 1:*, Single · a star, not a flat table
10
18 DAX measures in a separate _Measures table · the control totals matched to the cent
Power BI star schema: seven tables, six relationships
The star schema in Power BI — seven tables, six 1:* relationships around the fact table
Interactivity

A model that recalculates

This is not a picture — it is a live model. The same dashboard with two different filters gives two different answers.

Report filtered: Volvo FH, May 2026
Volvo FH · May 2026
Report filtered: Mercedes Actros trucks
Mercedes Actros · full period

On the left — Volvo FH in May: margin −€4,258, three loss-making trucks. On the right — Mercedes Actros: four trucks, margin +€18,001. The client buys not a picture, but a tool they will use themselves.

Impact

Before and after

Before — one overall number
2.4 % fleet margin
The number is correct, but useless: it does not say whether all trucks are equally weak or whether a few are dragging the rest to the bottom. The decision gets made on a hunch — usually the drivers get reviewed, because they are the easiest thing to see.

After — 6 of 24 and four causes
4 different causes
Six trucks run at a loss, and their causes differ: one has too low a rate, another too much empty running, a third fuel, a fourth a single €17,397 repair. Four problems that need four solutions — while the single 2.4 % figure blended them all into one.

In numbers

What the report reveals

−€26,436
the worst truck over 8 months — all three metrics red at once
2.6×
gap between the most and least expensive route (DE-BNL €2.69 vs LT-PL €1.04)
€17,397
a single repair that turned an average truck loss-making
19.5 %
empty running of the worst truck — every fifth kilometre without a load
A scatter chart of 1,744 trips showed what no summary figure reveals: the fleet runs two completely different businesses. Short 200–600 km trips at €2.4–3.0/km and long trips up to 3,000 km at €1.0–1.3/km — with almost nothing in between. Which means the “average rate of €1.30/km” is a number that almost no real trip actually matches.
Easily missed

Three traps the numbers don’t reveal on their own

A report that shows wrong numbers looks exactly as good as one that shows right numbers. In this project three errors were found after the visuals already looked finished — and not one of them would have given itself away.

1

The largest cost had dropped out

The “cost structure” showed eight types from accounting: leasing, insurance, tyres, repairs. The total looked reasonable. Only fuel was missing — because fuel comes from a different system. €1,145,310, or 47 % of the entire cost basket, simply was not on the chart. After the fix, the check: the sum of the nine bars matched total costs to the cent.

2

A correct grand total, every cell wrong

The “margin by customer and route” matrix showed roughly −€2.4M in every cell. The reason: customer and route live in the trips table, while costs live in their own, unrelated table. A filter by customer filtered revenue but not costs, so every cell received the whole fleet’s costs. The grand total was still correct, so at first glance nothing looked off. The fix was not technical: margin by route cannot be computed without an assumption about how to allocate costs — so the matrix shows revenue per loaded kilometre instead, with the limitation written on the methodology page.

3

A threshold that flagged the average

The fuel-cost limit was first set at 33 l/100 km. It lit up 9 of 24 trucks red — while the fleet average is 32.1. The threshold marked not a problem, but the average. Raised to 35. A second rule (“fuel overspend in euros > 0”) was removed entirely: it fired almost everywhere and repeated the same information.

All three were found because the numbers were checked back before they went into a visual — not after the report was already with the client.

Transparency

Methodology: how it was calculated

Which assumptions were applied and what this report does not calculate.

Data sources
  • TMS, trip management system — 1,744 trips: date, truck, route, customer, kilometres, revenue
  • Fuel-card statement — 868 refuels: date, card, litres, price, amount
  • Accounting — 192 rows: object, month, eight cost types

The three systems write the same truck differently — V-104, LT104, Volvo FH 104 (ABC104). They are joined through a hand-built truck reference table.

What is included in cost

Fuel, leasing or depreciation, insurance, repairs, tyres, driver costs with per-diems, road tolls and a share of administrative costs allocated to the truck.

Assumptions
  • Administrative costs allocated evenly — equally to each truck. In a real project this is the first question for the client: does the dispatcher’s time split evenly
  • Fuel norm for comparison — 30.5 l/100 km. The deviation from it is converted into euros using the average refuel price
  • Costs are recorded per truck and month, so all report filters work at month level
What this report does not calculate

Margin by customer or route cannot be computed — costs are not linked to a specific trip. So routes and customers are compared by revenue per loaded kilometre, not by margin.

For margin by route, you would need to agree on a cost-allocation rule, for example proportional to kilometres. That is an assumption, and it must be said out loud, not hidden inside a number.

January–August 2026
period
24
trucks
2,804
rows of data
3
systems merged
Note · demonstration report

All data used in this report is fictional, and the company “PARKAS 24” does not exist. The cost levels and metrics are calibrated against publicly available Lithuanian road-transport sector data so that the report looks and behaves like a real one. This is portfolio work, not the result of a real client.

Used

Technologies and methods

Power Query
Merge Queries
Unpivot Other Columns
Using Locale
Star schema model
DAX measures
Conditional formatting
Scatter chart
Synchronised filters
Data quality checks
Dashboard design
Power BI Desktop

Have a fleet but don’t know which truck earns?

Tell me what reports you get from your TMS, fuel cards and accounting — I will assess for free what can be joined together and what you would see then that you cannot see now.

Get a free assessment →

The example uses demonstration data.