Transaction Source Features

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

Each feature in ml_features is logged on several rows, and some of the rows whose source is 'user_sessions' were saved with no average value. Return the names of those features, each listed once, in alphabetical order.

One pipeline reviewed them. What did it see?

Tables

ml_features

Columns: feat_id INTEGER, feat_name TEXT, dtype TEXT, avg_val REAL, null_pct REAL, updated TEXT, source TEXT

ml_features: 10 of 200 rows
feat_idfeat_namedtypeavg_valnull_pctupdatedsource
141login_countint647.332026-02-02transactions
182cart_valuefloat3214.662026-03-03page_views
223page_dwellstring21.992026-04-04ad_impressions
264click_rateboolean29.2122026-05-05NULL
305days_activeFloat6436.5152026-06-06search_queries
346avg_orderINT6443.8182026-07-07orders
387session_lenfloat6451.1212026-08-08NULL
428scroll_pctint6458.4242026-09-09user_sessions
469bounce_cntfloat3265.7NULL2026-01-10transactions
510user_agestring73302026-02-11page_views

Expected output

First 4 of 4 rows
feat_name
avg_order
cart_value
click_rate
scroll_pct

Worked solution and explanation

What this really tests

This is a test for an absent value wearing a data-quality costume. The question is which session-sourced features never got an average written down, and SQL only answers that with avg_val IS NULL. Reach for avg_val = NULL and you get back nothing, because a comparison against NULL is never true, only unknown. The second tell is quieter: every feature name sits on more than one row in ml_features, so a query that does not collapse repeats hands back each name twice.


Working through it

Step 1: Keep only the session source

Filter on source = 'user_sessions'. It earns its place: the only other rows missing an average carry no source at all, and one of them is 'user_age', which slips into the list the moment this filter goes.

Step 2: Test for a missing average, not an equal one

avg_val IS NULL keeps the rows where no average was ever recorded. avg_val = NULL asks whether an unknown equals an unknown, the answer is unknown, and a filter only passes rows that are true.

Step 3: Collapse the repeats, then sort

Every qualifying name appears on two rows here, so SELECT DISTINCT feat_name folds each to one entry. The list is read alphabetically, so ORDER BY feat_name finishes it.


The solution

Source filter plus a null test, then dedup
SELECT DISTINCT feat_name
FROM ml_features
WHERE source = 'user_sessions'
  AND avg_val IS NULL
ORDER BY feat_name

Common follow-up questions