CAP 2791C Final Project · Power Query and data modeling
21 annual PDFs in three layouts, turned into one Power BI model: a handover to the colleague who maintains it next
Power BI: Data Preparation · Miami Dade College · Fall 2026
Part 1 · The business problem
Part 1 · The data
| County | Sex | 15 | 16 | … |
| Alachua | F | 583 | 959 | … |
| null | M | 572 | 933 | … |
| County | 15 | 16 | … |
| Alachua | … | … | … |
| F | … | … | … |
| M | … | … | … |
| County | Age | Female | Male |
| Alachua County | Age 15 | 612 | 565 |
| Alachua County | Age 16 | 922 | 855 |
SourceFilesQA ReconciliationPart 2 · Parameters
SourcePath the start of the path to the PDFs...\final-project\data\→ local copies, offline
https://www.flhsmv.gov/pdf/driver-vehiclereports/→ the original source
File_2006countysexage2006.pdfFile_2007countysexage2007.pdfFile_20262026annuallicenseddriverreport.pdf

Part 2 · Staging
SourceFiles turns 22 parameters into one table
SourcePath points at the FLHSMV web folder; Source Location shows where each year was read from.Web.Contents for http, Folder.Files otherwise; no firewall errorsPart 3 · Long layout, 2019–2026
fnParseLong, on one PDF.Column3 = "Female" and AgeBracket does not contain "to"._ada files. In the wide 2020 and 2021 files, the PDF connector merges the page header into the first row of each page, and that row's numbers are lost.Part 3 · Wide layout, 2006–2011 and 2018
The PDF table as Power Query reads it: the county is printed on the F row, with null on the M row.

Remove Empty drops the title; Use First Row as Headers turns the age brackets into column names.

Fill Down copies each county onto its M row.

Unpivot Other Columns, Replace Values (the dash printed for zero, F and M spelled out) and the type change: one row per county, sex and age bracket.

Part 4 · Stacked layout, 2012–2017
fnParseStackedPart 4 · Hand edits
| Parser | Years | Steps | Typed by hand ("M edit") |
|---|---|---|---|
fnParseLong | 2019–2026 | 14 | the year column |
fnParseWide | 2006–2011, 2018 | 19 | rename by position; label the statewide row; the year column |
fnParseStacked | 2012–2017 | 21 | rename by position; 2012 "21-30" to "22-30"; the year column |
Part 4 · Quality check
QA Reconciliation in Table view. Check it after every refresh.Part 5 · Star schema

| Table | Role | Rows |
|---|---|---|
| Licenses | fact: year, county, age bracket, sex, drivers | 43,080 |
| Year | dimension, with source file and bracket scheme | 21 |
| County | 67 counties, Out of State, Unknown | 69 |
| Age Bracket | every bracket as published | 28 |
| QA Reconciliation | standalone check | 21 |
Part 5 · Age brackets
| Years | Brackets above age 20 |
|---|---|
| 2006–2012 | single years to 21, then 22–30 |
| 2013 | 21–30 |
| 2014–2026 | 21–29 |
Above 20 the schemes cannot be mapped onto each other. Every bracket stays as published, and Age Group holds the only groups identical in all years:

Part 5 · Measures
Licensed Drivers =
VAR LatestYear = MAX ( 'Year'[Year] )
RETURN
CALCULATE ( SUM ( Licenses[Drivers] ), 'Year'[Year] = LatestYear )
Florida County Drivers =
CALCULATE ( [Licensed Drivers], 'County'[Is Florida County] = TRUE () )
Seven measures in two display folders: Drivers (Licensed, Female, Male, Florida County) and Change (Prior Year, YoY Change, YoY Change %).
Part 5 · Maintenance
data\under the file name FLHSMV publishesFile_2027 to Parameters - File NamesManage Parameters, New, type TextSourceFiles{2027, File_2027, "Long"}, or "Wide" or "Stacked" if the layout changes againQA Reconciliation2027 should read Reconciled with 68 counties; new county spellings go into CountyAliasesConclusion
SourcePath switches between the local copies and the FLHSMV website.Thank you. Questions?