Bird
Raised Fist0
dbtdata~10 mins

Custom singular tests in dbt - Step-by-Step Execution

Choose your learning style10 modes available

Start learning this pattern below

Jump into concepts and practice - no test required

or
Recommended
Test this pattern10 questions across easy, medium, and hard to know if this pattern is strong
Concept Flow - Custom singular tests
Write SQL query for test
Define test in schema.yml
Run dbt test command
dbt executes test query
Check if query returns rows
Test fails
Report result
This flow shows how you write a custom singular test as a SQL query, define it in dbt, run it, and dbt checks if the query returns any rows to decide pass or fail.
Execution Sample
dbt
SELECT id FROM {{ ref('customers') }} WHERE email IS NULL;

-- In schema.yml:
-- tests:
--   - custom_singular_test

-- Run: dbt test
This test checks if any customer has a NULL email; if yes, test fails.
Execution Table
StepActionSQL Query ResultTest OutcomeExplanation
1Run custom singular test queryReturns rows with ids 3, 7FailQuery found customers with NULL email
2dbt detects rows returnedRows existFailAny rows mean test fails
3Report test resultFailFailTest fails because condition is not met
4If no rows returnedNo rowsPassTest passes if query returns no rows
💡 Test stops after checking if query returns any rows; rows mean fail, no rows mean pass.
Variable Tracker
VariableStartAfter Query ExecutionFinal
query_result_rowsempty[3,7][3,7]
test_statusundefinedFailFail
Key Moments - 3 Insights
Why does the test fail if the query returns rows?
Because custom singular tests in dbt are designed so that returning any rows means the test condition is broken, as shown in execution_table step 2.
What if the query returns no rows?
If no rows are returned, it means the condition is met and the test passes, as explained in execution_table step 4.
How do you define a custom singular test in dbt?
You write a SQL query that returns rows when the test fails, then reference it in schema.yml under tests, as shown in execution_sample.
Visual Quiz - 3 Questions
Test your understanding
Look at the execution_table, what does dbt conclude when the query returns rows?
AThe test passes
BThe test fails
CThe test is skipped
DThe test is retried
💡 Hint
See execution_table row 2 where rows returned lead to test failure.
At which step does dbt decide the test outcome?
AStep 2
BStep 1
CStep 3
DStep 4
💡 Hint
Check execution_table row 2 where dbt detects rows and sets test status.
If the query returned no rows, what would be the test outcome?
AFail
BError
CPass
DUnknown
💡 Hint
Refer to execution_table row 4 where no rows means test passes.
Concept Snapshot
Custom singular tests in dbt:
- Write a SQL query returning rows if test fails
- Define test in schema.yml referencing the SQL
- Run 'dbt test' to execute
- If query returns rows, test fails
- If no rows, test passes
Full Transcript
Custom singular tests in dbt work by writing a SQL query that returns rows when a condition is broken. You define this test in your schema.yml file. When you run 'dbt test', dbt runs the query. If the query returns any rows, dbt marks the test as failed. If no rows are returned, the test passes. This method helps you check specific data quality rules easily by writing simple SQL queries.

Practice

(1/5)
1. What is the main purpose of a custom singular test in dbt?
easy
A. To automatically generate documentation for your models
B. To write your own SQL query that checks data quality and returns rows only if there are issues
C. To schedule dbt runs at specific times
D. To create new tables from existing data

Solution

  1. Step 1: Understand the role of custom singular tests

    Custom singular tests are SQL queries that check data quality by returning rows only when problems exist.
  2. Step 2: Compare options with this definition

    Only To write your own SQL query that checks data quality and returns rows only if there are issues describes writing a SQL query that returns rows if there are data issues, matching the purpose of custom singular tests.
  3. Final Answer:

    To write your own SQL query that checks data quality and returns rows only if there are issues -> Option B
  4. Quick Check:

    Custom singular test = SQL check returning problem rows [OK]
Hint: Custom singular tests return rows only when data has problems [OK]
Common Mistakes:
  • Confusing tests with documentation generation
  • Thinking tests create tables
  • Assuming tests schedule runs
2. Which of the following is the correct way to define a custom singular test in your schema.yml file?
easy
A. tests: - my_custom_test.sql
B. tests: - my_custom_test: sql: my_custom_test.sql
C. tests: - name: my_custom_test test: my_custom_test
D. tests: - my_custom_test

Solution

  1. Step 1: Recall the schema.yml syntax for custom singular tests

    Custom singular tests are referenced by their filename (without .sql) in the tests list of schema.yml.
  2. Step 2: Match options to this syntax

    tests: - my_custom_test correctly references the test file tests/my_custom_test.sql. Other options use incorrect structure, extra keys, or include .sql.
  3. Final Answer:

    tests: - my_custom_test -> Option D
  4. Quick Check:

    schema.yml test syntax = - test_filename_without_sql [OK]
Hint: Reference tests by name (no .sql) in tests: list [OK]
Common Mistakes:
  • Using 'name' or 'test' keys
  • Including .sql extension
  • Using map/dict structure
3. Given the following custom singular test SQL in tests/check_positive_values.sql:
SELECT * FROM {{ ref('orders') }} WHERE amount <= 0
What will be the output if all amounts in the orders table are positive?
medium
A. An empty result with zero rows
B. A table with all rows where amount is less than or equal to zero
C. An error because of invalid SQL syntax
D. A count of rows with amount less than or equal to zero

Solution

  1. Step 1: Understand the test SQL logic

    The test selects rows where amount is less than or equal to zero.
  2. Step 2: Analyze the data condition

    If all amounts are positive, no rows satisfy the condition, so the query returns zero rows.
  3. Final Answer:

    An empty result with zero rows -> Option A
  4. Quick Check:

    All positive amounts means zero rows returned [OK]
Hint: No matching rows means test passes with empty output [OK]
Common Mistakes:
  • Expecting a count instead of rows
  • Thinking it returns all rows
  • Assuming SQL syntax error
4. You wrote a custom singular test SQL file but when running dbt test, it fails with a syntax error. Which of the following is the most likely cause?
medium
A. The model referenced in {{ ref() }} does not exist
B. The test SQL returns zero rows
C. The SQL file is missing the required SELECT statement
D. The test is not listed in schema.yml

Solution

  1. Step 1: Identify causes of SQL syntax errors

    Syntax errors happen when SQL is malformed, such as missing SELECT statements.
  2. Step 2: Evaluate options for syntax error causes

    The SQL file is missing the required SELECT statement directly relates to SQL syntax. Other options cause runtime or configuration errors, not syntax errors.
  3. Final Answer:

    The SQL file is missing the required SELECT statement -> Option C
  4. Quick Check:

    Syntax error = malformed SQL like missing SELECT [OK]
Hint: Syntax errors usually mean SQL is incomplete or malformed [OK]
Common Mistakes:
  • Confusing missing test listing with syntax error
  • Assuming zero rows cause syntax errors
  • Ignoring missing model references
5. You want to create a custom singular test that checks if any user has a NULL email in the users table. Which SQL query should you write in your test file?
hard
A. SELECT * FROM {{ ref('users') }} WHERE email IS NULL
B. SELECT COUNT(*) FROM {{ ref('users') }} WHERE email IS NULL
C. SELECT email FROM {{ ref('users') }} WHERE email IS NOT NULL
D. SELECT * FROM {{ ref('users') }} WHERE email = ''

Solution

  1. Step 1: Understand the test goal

    The test should return rows where email is NULL to detect missing emails.
  2. Step 2: Choose the SQL that returns rows with NULL emails

    SELECT * FROM {{ ref('users') }} WHERE email IS NULL returns rows only when there are NULL emails (0 rows = pass). COUNT(*) always returns one row, failing even with zero NULLs. IS NOT NULL selects good rows (opposite). = '' checks empty strings, not NULLs.
  3. Final Answer:

    SELECT * FROM {{ ref('users') }} WHERE email IS NULL -> Option A
  4. Quick Check:

    Return rows with NULL email = SELECT * FROM {{ ref('users') }} WHERE email IS NULL [OK]
Hint: Use SELECT * WHERE column IS NULL to find missing values [OK]
Common Mistakes:
  • Using COUNT(*) instead of returning rows
  • Checking for empty string instead of NULL
  • Selecting non-NULL emails