Below the Line

An easy SQL interview practice problem on DataDriven. Write the query and run it against a real database, with instant feedback.

Domain
SQL
Difficulty
easy
Seniority
L3

Problem

Severity in dq_checks is a free-text label rather than a fixed list, and every row is one check run stamped with its full run_at timestamp. Count the 2026 runs that came in at the 'low' severity tier.

Low severity. High volume.

Tables

dq_checks

Columns: check_id INTEGER, tbl_name TEXT, col_name TEXT, rule TEXT, passed INTEGER, fail_pct REAL, run_at TEXT, severity TEXT

dq_checks: 10 of 200 rows
check_idtbl_namecol_namerulepassedfail_pctrun_atseverity
131usersemailunique1NULL2026-02-02 01:00:00high
162productsamountrange1NULL2026-03-03 02:00:00medium
193transactionsstatusformat1NULL2026-04-04 03:00:00low
224eventscreated_atreferential1NULL2026-05-05 04:00:00Critical
255sessionspricefreshness0152026-06-06 05:00:00HIGH
286ad_impressionsregionNot_Null1NULL2026-07-07 06:00:00critical
317ordersuser_idUNIQUE102026-08-08 07:00:00high
348usersemailnot_null1NULL2026-09-09 08:00:00medium
379productsamountunique1NULL2026-01-10 09:00:00low
410transactionsstatusrange0302026-02-11 10:00:00Critical

Expected output

First 1 of 1 rows
low_severity_count
20

Worked solution and explanation

What they are really testing

This is a year-scoped count dressed up as a data-quality report. Everyone writes the severity filter; the probe is run_at. It is a full text timestamp, and dq_checks reaches from 2022 through 2026, so the year has to be pulled out of it before you compare. Compare the whole timestamp to '2026' and you get 0, which reads like a quiet year instead of a bug. Forget the year entirely and you get 34, because 14 low runs from earlier years ride along with the 20 that belong to 2026.

Step 1: Pull the year out of run_at

strftime('%Y', run_at) turns each timestamp into its four-digit year, and that is what you compare to '2026'. A timestamp is not a year: equality against the full string can never match.

Step 2: Pin the low tier

severity is free text: other tiers arrive in two casings ('Critical' and 'critical', 'HIGH' and 'high'). On this data the low tier only ever arrives as 'low', so LIKE 'low%' and = 'low' agree. The prefix pattern keeps the filter from depending on that staying true.

Step 3: Count every surviving run

With both conditions in the WHERE, COUNT(*) over what remains is the answer. Each row is one execution, so repeated runs of the same rule each count, and passed and failed runs count alike.

Low-tier check runs for the target year
SELECT COUNT(*) AS low_severity_count
FROM dq_checks
WHERE severity LIKE 'low%'
  AND strftime('%Y', run_at) = '2026';

The prefix pattern pins the low tier; strftime pulls the year out of run_at before comparing.

Compares the timestamp to the year
WHERE severity = 'low' AND run_at = '2026' asks whether '2026-04-04 03:00:00' equals '2026'. It never does, so the count is 0.
Extracts the year first
WHERE severity LIKE 'low%' AND strftime('%Y', run_at) = '2026' compares year to year, so the 20 low runs of 2026 survive and the earlier years drop out.

Common follow-up questions