SQL Style Guide Template
Three documents and three sheets that turn a model's test status into a fix priority once you know what it actually feeds.
Free download · No account needed
Test Coverage by Model
One row per model, two facts checked separately
Filled in after the standards scan, not instead of it. A model earns its priority from what it actually feeds, never from a test count alone.
Any Test at All
The project-wide question a coverage percentage already answers: does at least one test exist anywhere on this model, on any column.
Primary Key Verified
Checked separately, because a test on a convenient column is not the same claim: does the model's actual grain carry a real unique and not_null check.
Feeds an Exposure
Board-level, executive-facing, internal-only, or none. This is the column a coverage percentage has no way to see.
Priority
Critical, High, Medium or Covered, derived from the two checks above rather than assigned by hand.
dbt's own style guide already settles most of this. Name every CTE after the ref or source it wraps, keep every join explicit, use an explicit `as` on every alias, and a linter enforces all of it once a team writes the rules down once. SQL and Model Standards and the Review Checklist in this pack are that write-down. Getting a warehouse to agree on formatting was never the hard part, and a linter catches most of it on every pull request without a person reading a single line.
Testing is closer to solved than it looks, too. dbt's own project-evaluator package reports test_coverage_pct, the percentage of models carrying at least one test, and separately flags every model missing a real check on its primary key. At Kettlewell Logistics, a fictional freight company, that gap is real: 70.8 percent of 96 models read as tested, and only 45.8 percent have their actual primary key verified.
dbt's own exposures feature already lets a model declare a downstream dashboard, typed and rated by maturity. Nothing joins that declaration to the missing-test list. Test Coverage by Model is that join: of Kettlewell's 52 models with an unverified key, 15 feed a board or executive dashboard directly. Built for the engineer reviewing someone else's pull request and the lead deciding what to fix before Monday's board deck runs, before the query's own cost is even a question.
What's in the pack
SQL and Model Standards
Naming by layer, explicit columns and joins, no hardcoded literals, written down once so a review stops relitigating the same fix.
Review Checklist
What blocks a merge versus what gets a follow-up, including whether every downstream reader was re-verified after a grain change.
Testing Guidance
The layer-by-layer minimum test, and the rule for turning a primary key gap into Critical, High, Medium or Covered.
Standards Compliance Scan
One row per model against the standards document: naming, explicit columns, explicit joins, hardcoded literals, and a description check.
Common Issue Register
Every recurring style failure ranked by how many models it touches, with one real example and the exact fix, a different gap than a missing column definition.
Test Coverage by Model
Every model's real primary key test status, joined to whether it feeds a board, an executive dashboard, or nothing at all.
How to use it
- 1
Open in River, or take it blank
Claim the pack in River and hand it the repository, or take the blank documents and sheets and fill them in yourself.
- 2
Send the repository
A dbt project, a sample of model files and schema definitions, or whatever your transformation tool exports. Partial is fine and gets said.
- 3
Name what it feeds
Which models feed a dashboard, a scheduled report, or a recurring review, and which of those a board member or executive actually reads.
- 4
Get the fix list
The Test Coverage by Model sheet, ordered by what breaks something somebody looks at, not by how many models are untested.
Frequently asked questions
Is this template free?
Yes, no account or card needed to download it. Edit with AI is the optional half, where River reads your repository and builds the scan and the coverage sheet itself. Every other pack sits in the template library.
What format are the downloaded files?
Three documents as Word files and three sheets as CSVs, zipped together. The sheets ship with Kettlewell Logistics' illustrative rows in place, so the priority split is visible before you replace them with your own models.
dbt already reports a test coverage percentage. Why do we need this?
That percentage counts any model with at least one test, on any column. It says nothing about whether the test landed on the model's actual primary key, and nothing about whether the model feeds anything a person answers to. This pack checks both, separately, and only then assigns a priority.
We haven't declared exposures in dbt. Can we still build the coverage sheet?
Yes. An exposure declaration is one way to know what a model feeds, not the only way. Naming what shows up in a board deck or a recurring review by asking the people who run those meetings gets to the same answer directly.
Does this replace a SQL linter?
No, it's the standards document a linter enforces. Most of SQL and Model Standards, naming, explicit columns, explicit joins, formatting, is mechanical enough to lint automatically once it's written down; the primary key and exposure questions still need a person.
Can a well-tested model still come out as a priority?
No, and the sheet says so directly: a verified primary key marks a model Covered regardless of what it feeds. The reverse is the actual finding, a model with several tests, none of them on its real grain, feeding something important.
Our model repository can't leave our network. Can we still use this?
Yes. A private AI workspace runs the scan and builds the coverage sheet inside your own tenancy, so model code and schema names never cross a boundary your data governance hasn't approved. The scan, the register and the sheet behave exactly as described here.
Find out which untested models are one bad number away from a board meeting
Start from the blank documents and sheets, or send River your repository and let it join what's untested to what it actually feeds.
Edit with AI