The EXISTS predicate returns TRUE when a subquery returns at least one row, and FALSE when it returns zero rows. It is typically combined with a correlated subquery, which brings columns from the outer query into the inner subquery.
WHERE EXISTS ( SELECT 1 -- The SELECT value is not evaluated (1, *, and NULL all behave the same) FROM orders o WHERE o.user_id = u.user_id -- Correlation condition: bring outer u into the inner query AND o.status = 'completed' )
COUNT(*) > 0.From the users table, retrieve users who have at least one completed order. Return user_id, name, plan, ordered by user_id ascending.
| user_id | name | plan |
|---|---|---|
| 1 | Taro Tanaka | premium |
| 2 | Hanako Sato | free |
| 3 | Ichiro Suzuki | premium |
| 4 | Jiro Yamada | free |
| 5 | Saburo Takahashi | free |
| order_id | user_id | amount | status | ordered_at |
|---|---|---|---|---|
| 101 | 1 | 15000 | completed | 2024-05-01 |
| 102 | 1 | 8000 | cancelled | 2024-05-10 |
| 103 | 2 | 5000 | pending | 2024-05-15 |
| 104 | 3 | 22000 | completed | 2024-05-20 |
| 105 | 4 | 3000 | cancelled | 2024-05-22 |
| 106 | 3 | 9000 | completed | 2024-05-25 |
| 107 | 5 | 12000 | completed | 2024-05-28 |
Expected output (user_id ascending):
| user_id | name | plan |
|---|---|---|
| 1 | Taro Tanaka | premium |
| 3 | Ichiro Suzuki | premium |
| 5 | Saburo Takahashi | free |
Note: user 2 has only a pending order, and user 4 only a cancelled order → no completed order → excluded.
- Read every model answer, explanation and table-transition visualization across all 48 advanced sets (240 questions)
- One-time purchase — no subscription. Future advanced sets are included
- Background, problem and expected output stay free
NOT EXISTS returns rows for which no matching row exists. It is the anti-join pattern, the counterpart to INNER JOIN.
WHERE NOT EXISTS ( SELECT 1 FROM order_items oi WHERE oi.product_id = p.product_id -- FALSE if even one match exists; TRUE if none exists )
x <> NULL is UNKNOWN, so the whole AND expression is UNKNOWN → every row is excluded. NOT EXISTS avoids this trap.From the products table, retrieve products that have never been ordered. Use NOT EXISTS to check order_items, return product_id, name, category, price, and order by product_id ascending.
| product_id | name | category | price |
|---|---|---|---|
| 1 | Smartphone X | Smartphone | 89800 |
| 2 | Smartbook Pro | PC | 128000 |
| 3 | Tablet Air | Tablet | 64800 |
| 4 | Wireless Earbuds | Accessories | 12800 |
| 5 | USB Cable | Accessories | 980 |
| 6 | Gaming PC Pro | PC | 198000 |
| item_id | order_id | product_id | quantity |
|---|---|---|---|
| 1 | 101 | 1 | 1 |
| 2 | 101 | 4 | 2 |
| 3 | 104 | 2 | 1 |
| 4 | 106 | 3 | 1 |
| 5 | 107 | 1 | 1 |
| 6 | 105 | NULL | 1 |
Note: item 6 references a deleted product → product_id = NULL.
Expected output (product_id ascending):
| product_id | name | category | price |
|---|---|---|---|
| 5 | USB Cable | Accessories | 980 |
| 6 | Gaming PC Pro | PC | 198000 |
Note: products 1, 2, 3, and 4 appear in order_items and are excluded. Products 5 and 6 have never been ordered.
- Read every model answer, explanation and table-transition visualization across all 48 advanced sets (240 questions)
- One-time purchase — no subscription. Future advanced sets are included
- Background, problem and expected output stay free
IN (subquery) checks whether a column value belongs to the set returned by a subquery. It is common in production because it dynamically derives a set from the table's current state instead of using a fixed list.
WHERE o.user_id IN ( SELECT user_id -- Dynamically generate the ID list of premium members with a subquery FROM users WHERE plan = 'premium' ) -- ↑ Non-correlated subquery: evaluated once to build the set; often equivalent to EXISTS
NOT IN becomes UNKNOWN for every row → zero rows (see Q2). Always use NOT EXISTS, or add WHERE col IS NOT NULL before using NOT IN.From the orders table, retrieve orders placed by premium members (plan = 'premium'). Use a subquery against users, return order_id, user_id, amount, status, ordered_at, and order by ordered_at ascending.
| order_id | user_id | amount | status | ordered_at |
|---|---|---|---|---|
| 101 | 1 | 15000 | completed | 2024-05-01 |
| 102 | 1 | 8000 | cancelled | 2024-05-10 |
| 103 | 2 | 5000 | pending | 2024-05-15 |
| 104 | 3 | 22000 | completed | 2024-05-20 |
| 105 | 4 | 3000 | cancelled | 2024-05-22 |
| 106 | 3 | 9000 | completed | 2024-05-25 |
| 107 | 5 | 12000 | completed | 2024-05-28 |
| user_id | name | plan |
|---|---|---|
| 1 | Taro Tanaka | premium |
| 2 | Hanako Sato | free |
| 3 | Ichiro Suzuki | premium |
| 4 | Jiro Yamada | free |
| 5 | Saburo Takahashi | free |
Expected output (ordered_at ascending):
| order_id | user_id | amount | status | ordered_at |
|---|---|---|---|---|
| 101 | 1 | 15000 | completed | 2024-05-01 |
| 102 | 1 | 8000 | cancelled | 2024-05-10 |
| 104 | 3 | 22000 | completed | 2024-05-20 |
| 106 | 3 | 9000 | completed | 2024-05-25 |
Note: orders 103, 105, and 107 from user_ids 2 (free), 4 (free), and 5 (free) are excluded.
- Read every model answer, explanation and table-transition visualization across all 48 advanced sets (240 questions)
- One-time purchase — no subscription. Future advanced sets are included
- Background, problem and expected output stay free
ANY (= SOME) returns TRUE when a comparison is true for at least one row in the subquery's set; ALL returns TRUE only when it is true for every row.
WHERE price > ANY (SELECT price FROM products WHERE category = 'Accessories') -- ↑ Equivalent to price > MIN(accessory prices): “greater than any” means greater than the smallest value in the set WHERE price > ALL (SELECT price FROM products WHERE category = 'Accessories') -- ↑ Equivalent to price > MAX(accessory prices): “greater than all” means greater than the largest value in the set
category = ANY (ARRAY['PC', 'Tablet']) is exactly equivalent to IN ('PC', 'Tablet'). ANY / ALL show their real value when used with comparison operators such as > and <.From the products table, retrieve products priced higher than every product in the Accessories category using the ALL predicate. Return product_id, name, category, price, ordered by price ascending.
| product_id | name | category | price | stock |
|---|---|---|---|---|
| 1 | Smartphone X | Smartphone | 89800 | 50 |
| 2 | Smartbook Pro | PC | 128000 | 0 |
| 3 | Tablet Air | Tablet | 64800 | 30 |
| 4 | Wireless Earbuds | Accessories | 12800 | 100 |
| 5 | USB Cable | Accessories | 980 | 200 |
| 6 | Gaming PC Pro | PC | 198000 | 5 |
Expected output (price ascending):
| product_id | name | category | price |
|---|---|---|---|
| 3 | Tablet Air | Tablet | 64800 |
| 1 | Smartphone X | Smartphone | 89800 |
| 2 | Smartbook Pro | PC | 128000 |
| 6 | Gaming PC Pro | PC | 198000 |
Note: the maximum Accessories price is 12,800 yen. The 4 products above satisfy price > ALL {12800, 980} = price > 12800.
Product 4 (12800) fails because 12800 > 12800 is false; product 5 (980) fails both comparisons → excluded.
- Read every model answer, explanation and table-transition visualization across all 48 advanced sets (240 questions)
- One-time purchase — no subscription. Future advanced sets are included
- Background, problem and expected output stay free
IS DISTINCT FROM is a predicate for safely comparing equality when NULL may be present. Ordinary <> produces UNKNOWN when compared with NULL and the row is excluded, whereas IS DISTINCT FROM treats NULL as a “definitely different value” and returns TRUE.
-- Truth table for a IS DISTINCT FROM b 'WINTER20' IS DISTINCT FROM 'SUMMER10' -- → TRUE (different values) NULL IS DISTINCT FROM 'SUMMER10' -- → TRUE (NULL is treated as different) 'SUMMER10' IS DISTINCT FROM 'SUMMER10' -- → FALSE (same value) NULL IS DISTINCT FROM NULL -- → FALSE (both NULL are treated as equal)
coupon_code <> 'SUMMER10', rows where coupon_code is NULL evaluate to UNKNOWN → excluded. Use IS DISTINCT FROM when you also want to include rows where the coupon was unused (NULL).From the orders table, retrieve orders whose coupon_code differs from 'SUMMER10', including rows where the coupon was unused (NULL). Use IS DISTINCT FROM, return order_id, user_id, amount, coupon_code, ordered_at, and order by order_id ascending.
| order_id | user_id | amount | coupon_code | ordered_at |
|---|---|---|---|---|
| 101 | 1 | 15000 | SUMMER10 | 2024-05-01 |
| 102 | 1 | 8000 | NULL | 2024-05-10 |
| 103 | 2 | 5000 | NULL | 2024-05-15 |
| 104 | 3 | 22000 | WINTER20 | 2024-05-20 |
| 105 | 4 | 3000 | NULL | 2024-05-22 |
| 106 | 3 | 9000 | NULL | 2024-05-25 |
| 107 | 5 | 12000 | SUMMER10 | 2024-05-28 |
Expected output (order_id ascending):
| order_id | user_id | amount | coupon_code | ordered_at |
|---|---|---|---|---|
| 102 | 1 | 8000 | NULL | 2024-05-10 |
| 103 | 2 | 5000 | NULL | 2024-05-15 |
| 104 | 3 | 22000 | WINTER20 | 2024-05-20 |
| 105 | 4 | 3000 | NULL | 2024-05-22 |
| 106 | 3 | 9000 | NULL | 2024-05-25 |
Note: orders 101 and 107 (SUMMER10) are excluded. NULL rows (102, 103, 105, and 106) are included as “different from SUMMER10.”
- Read every model answer, explanation and table-transition visualization across all 48 advanced sets (240 questions)
- One-time purchase — no subscription. Future advanced sets are included
- Background, problem and expected output stay free