solulubeta
Sign in
SQL / Subqueries & CASE
05.01 · Lesson

Subqueries and CASE

Queries inside queries, correlated subqueries, CASE labels, date arithmetic and GREATEST.

3 min Free

This lesson covers scalar subquery, IN / EXISTS, correlated subquery, CASE WHEN, date arithmetic, GREATEST / LEAST. Read it, then solve questions 41–50 below it in the sidebar. Every query runs on a real PostgreSQL database inside your browser.

A subquery as a value

A SELECT in brackets that returns one value can be used wherever a number could: WHERE x > (SELECT AVG(x) FROM t). This is how you compare rows with an aggregate, which WHERE can’t do directly.

SELECT product_name, unit_price
FROM products
WHERE unit_price < (SELECT AVG(unit_price) FROM products);

A subquery as a list: IN and EXISTS

WHERE id IN (SELECT id FROM …) keeps rows whose id appears in the subquery’s result. EXISTS (SELECT 1 FROM … WHERE …) is true when the subquery returns any row. NOT IN breaks if the list contains a NULL; NOT EXISTS doesn’t.

SELECT customer_name
FROM customers c
WHERE EXISTS (
  SELECT 1 FROM sales s
  WHERE s.customer_id = c.customer_id AND s.quantity_sold >= 5
);

Correlated subqueries

A subquery that refers to the outer row (like c.customer_id above) is re-evaluated for each row. Use it to compare a row with its own group, e.g. “products cheaper than their category’s average”.

SELECT category, product_name, unit_price
FROM products p
WHERE unit_price < (
  SELECT AVG(unit_price) FROM products p2 WHERE p2.category = p.category
);

Labels with CASE

CASE WHEN cond1 THEN a WHEN cond2 THEN b ELSE c END returns the value of the first true condition. Without ELSE, unmatched rows get NULL.

SELECT customer_name,
       CASE WHEN joined_on < '2024-01-01' THEN 'Old-timer'
            ELSE 'New'
       END AS member_type
FROM customers;

Date arithmetic

In PostgreSQL date - date is a whole number of days and date + 7 is a week later. EXTRACT(ISODOW FROM d) is 1 (Monday) … 7 (Sunday). MySQL spells these DATEDIFF(a, b) and DAYOFWEEK(d) (1 = Sunday).

SELECT customer_name,
       joined_on,
       DATE '2024-04-01' - joined_on AS days_as_member,
       TO_CHAR(joined_on, 'Day') AS weekday
FROM customers;

Largest of several values

MAX() works down a column. To pick the larger of several values in the same row, use GREATEST(a, b, …); LEAST gives the smallest.

SELECT sale_id, quantity_sold,
       GREATEST(quantity_sold, 3) AS at_least_three,
       LEAST(quantity_sold, 5) AS at_most_five
FROM sales
LIMIT 6;
Mark this as done when you are finished.

Item 45 of 77 · updated 2026-10-12