Recent chats
ASKGEEZ Q&A GUIDETechnology & devices

How can I use a scalar subquery to show a related summary beside each row?

Quick answer

In SQLite, put a one-column subquery in the SELECT list, then refer to the current outer row inside the subquery’s WHERE clause. For example, match each product’s category to other products’ categories and calculate AVG(price). The subquery is correlated because it uses the outer product’s category, so the comparison value varies by category. This example describes SQLite behavior, not every database.

LET’S WORK THROUGH IT

The question, the details, the next step.

Question

I have a products table with a product name, category, and price. I want each product row to show the average price for its category beside its own price. Can I do that without grouping away the individual products?

Geez

Yes. In SQLite, place a scalar subquery in the SELECT list. The outer query still returns product rows, while the subquery calculates a value to display alongside each one:

SELECT
  p.name,
  p.category,
  p.price,
  (
    SELECT AVG(p2.price)
    FROM products AS p2
    WHERE p2.category = p.category
  ) AS category_avg
FROM products AS p;

The key comparison is p2.category = p.category. p2 names rows being examined inside the subquery; p names the current row from the outer query. SQLite permits a scalar subquery to refer to outer-query columns. Since the subquery returns one column, its result can be used as a value in the SELECT list. [S1]

For an illustrative dataset, assume the products are “Mug” at 10 and “Bottle” at 14 in “Drinkware,” and “Notebook” at 6 in “Paper.” The result would pair Mug with 12, Bottle with 12, and Notebook with 6 as their category averages. These names and prices are made-up examples, not data from a real store.

Follow-up question

How does the query know which category average to calculate for each row? I’m unsure which part changes as it moves through the products.

Geez

The outer row supplies the changing value. When the outer row is Mug, p.category is “Drinkware,” so the subquery’s filter compares p2.category with “Drinkware.” For Notebook, p.category is “Paper,” so the filter instead selects rows in “Paper.” That reference from inside the subquery to p.category outside it is the correlation.

You can read the names as separate roles: p is the product currently being returned; p2 is a candidate product considered for the summary. The AVG is calculated over the prices that pass the category match. SQLite describes correlated subqueries as being reevaluated whenever their result is required. That describes SQL semantics; it does not establish how fast the query will run or how another database handles it. [S1]

Follow-up question

What does the word “scalar” mean here, and what if there are no matching products?

Geez

A scalar subquery is used as a single value in an expression. SQLite’s rule is that a one-column subquery supplies the first row’s value, or NULL if it returns no rows. [S1] In this example, AVG provides a summary of the prices that match the category. For a non-aggregate subquery that can return multiple rows, the SQLite rule about taking the first row matters, so make sure the result you intend is genuinely one value rather than relying on a particular match.

In the shown query, a product normally matches its own category because its row is in products. If your real query uses a different table or additional filters, it may return no rows. In that case, SQLite’s scalar-subquery rule gives a NULL result. Decide whether that is appropriate for your report rather than treating it as zero.

Follow-up question

How can I adapt this to my table, and what should I check if the number looks wrong?

Geez

Replace products, name, category, and price with your actual table and column names, keeping the two aliases distinct. Then check the intended comparison group: if the summary should be by category, compare categories; if it should be by another grouping, correlate on that field instead. For the made-up example, the hand-calculated check is that both Drinkware rows show 12, while the Paper row shows 6.

Also inspect which rows contribute to the average. A filter added inside the subquery changes which prices contribute; a filter added only to the outer query changes which product rows are displayed. The SQLite description establishes the subquery behavior above, but does not establish performance, indexing needs, or whether other SQL engines use identical semantics. Check the query with a small set of rows whose expected result you can calculate by hand.

A practical checklist

  • Give the outer table a clear alias, such as p, and use a different alias such as p2 inside the subquery.

  • Select the product columns and scalar subquery value together in the outer SELECT list.

  • Match the intended grouping field in the subquery’s WHERE clause, such as p2.category = p.category.

  • Use a one-column subquery and name its result with a helpful alias such as category_avg.

  • Check a small hand-calculated example and consider what NULL would mean if the subquery returns no rows.

A few more useful answers

Why is this called a correlated subquery?

It refers to an outer-query column—in this example, p.category—so its result depends on the current outer product row.

Does this query guarantee good performance?

No. The cited SQLite description explains semantics, not performance guarantees. Check the query with your actual data and SQLite setup.

Can I use this exact query in every database?

The example and cited behavior are specifically for SQLite. Other database systems may differ, so check the documentation for the system you use.

Sources

References used for this guide.

  1. [S1] SQLite SQL Language Expressions: Scalar and Correlated Subqueries
    sqlite.org · Checked

YOUR QUESTION. YOUR DETAILS.

Let’s work through your situation.

Get a tailored answer or help with your next task. Starts at $1, with a quote before you pay.

Ask your own question
← Back to Geez at Work