The LIKE predicate checks whether a string matches a pattern. It has two wildcards: % (any string of zero or more characters) and _ (any single character). Combined with EXISTS, it enables practical compound filters such as “name matches a pattern × has a purchase history.”
-- % : any string of zero or more characters WHERE name LIKE 'T%' -- starts with 'T' (prefix match) — index usable WHERE name LIKE '%T%' -- contains 'T' (infix match) — index not usable -- _ : any single character WHERE code LIKE 'A_01' -- A?01 format (? is any one character) -- ILIKE: case-insensitive (PostgreSQL-specific) WHERE email ILIKE '%@example.com'
From the users table, retrieve users whose name starts with 'T' (LIKE 'T%') and who have at least one completed order. Return user_id, name, email, ordered by user_id ascending.
| user_id | name | plan | |
|---|---|---|---|
| 1 | Taro Tanaka | tanaka@example.com | premium |
| 2 | Hanako Sato | sato@example.com | standard |
| 3 | Ichiro Tamura | tamura@example.com | free |
| 4 | Jiro Yamada | yamada@example.com | premium |
| 5 | Saburo Ito | ito@example.com | premium |
| order_id | user_id | status |
|---|---|---|
| 101 | 1 | completed |
| 102 | 2 | completed |
| 103 | 3 | completed |
| 104 | 3 | completed |
| 105 | 4 | cancelled |
| 106 | 5 | pending |
Expected output (user_id ascending):
| user_id | name | |
|---|---|---|
| 1 | Taro Tanaka | tanaka@example.com |
| 3 | Ichiro Tamura | tamura@example.com |
Note: user 2 (Sato → starts with 'S'), user 4 (Yamada → starts with 'Y'), and user 5 (Ito) do not match LIKE 'T%' and 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
BETWEEN is a concise predicate for range conditions. a BETWEEN x AND y is equivalent to a >= x AND a <= y, a closed interval that includes both endpoints. Combined with NOT EXISTS, it enables inventory and sales-analysis queries such as “price band × no sales history.”
-- BETWEEN: a closed interval including both endpoints (x, y) WHERE price BETWEEN 3000 AND 7000 -- equivalent to >= 3000 AND <= 7000 -- NOT BETWEEN: outside the range WHERE price NOT BETWEEN 3000 AND 7000 -- equivalent to < 3000 OR > 7000 -- Caution for date ranges (timestamp type) WHERE created_at BETWEEN '2024-01-01' AND '2024-01-31' -- for timestamp, this reaches only '2024-01-31 00:00:00' → orders later that day are missed -- correct: created_at >= '2024-01-01' AND created_at < '2024-02-01'
>= start AND < end+1 is safer for date ranges.From the products table, retrieve products in the 'Accessories' category with price from 3,000 to 7,000 (BETWEEN) that have no completed orders, using NOT EXISTS. Return product_id, name, price, stock, ordered by price ascending.
| product_id | name | category | price | stock |
|---|---|---|---|---|
| 1 | Wireless Mouse | Accessories | 3500 | 80 |
| 2 | Mechanical Keyboard | Accessories | 8800 | 45 |
| 3 | HDMI Cable 2m | Accessories | 1200 | 150 |
| 4 | 7-Port USB Hub | Accessories | 4200 | 30 |
| 5 | External SSD 1TB | Storage | 9800 | 20 |
| 6 | HD Webcam | Accessories | 6500 | 15 |
| order_id | product_id | status |
|---|---|---|
| 101 | 4 | completed |
| 102 | 6 | pending |
| 103 | 1 | cancelled |
Expected output (price ascending):
| product_id | name | price | stock |
|---|---|---|---|
| 1 | Wireless Mouse | 3500 | 80 |
| 6 | HD Webcam | 6500 | 15 |
Note: product 4 (7-Port USB Hub) has completed order 101 → NOT EXISTS=FALSE and is excluded. Product 2: 8800 > 7000 / product 3: 1200 < 3000 → outside BETWEEN. Product 5 is in the Storage category.
- 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 SQL's three-valued logic (TRUE / FALSE / UNKNOWN), every comparison with NULL returns UNKNOWN. In a WHERE clause, UNKNOWN excludes a row just like FALSE. To test whether a value is NULL, using IS NULL / IS NOT NULL is essential.
-- ✗ = NULL always produces UNKNOWN (never use it) WHERE shipped_at = NULL -- always UNKNOWN → all rows excluded (the opposite of the intent) WHERE shipped_at <> NULL -- always UNKNOWN → all rows excluded -- ✓ IS NULL / IS NOT NULL are the only correct forms WHERE shipped_at IS NULL -- keep only NULL rows (find unshipped orders) WHERE shipped_at IS NOT NULL -- keep only non-NULL rows (shipped orders) -- NULL propagates through expressions SELECT amount + discount_amount -- discount is NULL → the result is also NULL SELECT COALESCE(discount_amount, 0) -- replace NULL with a fallback value using COALESCE
NULL = NULL evaluates to UNKNOWN, not TRUE. NULL values are not considered equal to one another. In PostgreSQL, NULL IS NOT DISTINCT FROM NULL compares two NULLs as equal.From the orders table, retrieve orders where status is 'processing' and shipped_at is NULL (unshipped), limited to orders from users whose plan is 'premium'. Use an IN subquery. Return order_id, user_id, amount, status, ordered by amount descending.
| order_id | user_id | amount | status | shipped_at |
|---|---|---|---|---|
| 101 | 1 | 8000 | completed | 2024-01-15 |
| 102 | 2 | 5000 | processing | NULL |
| 103 | 1 | 12000 | processing | NULL |
| 104 | 3 | 3000 | completed | 2024-01-20 |
| 105 | 4 | 9500 | processing | 2024-01-25 |
| 106 | 3 | 7000 | processing | NULL |
| user_id | name | plan |
|---|---|---|
| 1 | Taro Tanaka | premium |
| 2 | Hanako Sato | premium |
| 3 | Ichiro Suzuki | standard |
| 4 | Jiro Yamada | free |
Expected output (amount descending):
| order_id | user_id | amount | status |
|---|---|---|---|
| 103 | 1 | 12000 | processing |
| 102 | 2 | 5000 | processing |
Note: orders 101 and 104 are completed → excluded. Order 105 has shipped_at=2024-01-25 (non-NULL) → it does not match IS NULL and is excluded. Order 106 has user_id=3 (standard) → it is outside the IN list.
- 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
The ANY predicate (also written SOME) returns TRUE when the comparison is TRUE for at least one value from the subquery. The ALL predicate returns TRUE only when the comparison is TRUE for every value from the subquery.
-- ANY: TRUE if the comparison is TRUE for one value → equivalent to a chain of ORs WHERE price < ANY (SELECT price FROM competitor) -- ↑ equivalent: WHERE price < (SELECT MAX(price) FROM competitor) -- ALL: TRUE if the comparison is TRUE for every value → equivalent to a chain of ANDs WHERE price > ALL (SELECT price FROM competitor) -- ↑ equivalent: WHERE price > (SELECT MAX(price) FROM competitor) -- Special equivalences WHERE col = ANY (list) -- equivalent to = IN (list) WHERE col <> ALL (list) -- equivalent to = NOT IN (list) (NULL trap applies)
val <> NULL becomes UNKNOWN and the entire ALL result becomes FALSE. Since <> ALL (the equivalent of NOT IN) can exclude every row when NULL is present, prefer NOT EXISTS in production.From the products table (our products), retrieve products that are cheaper than at least one same-category competitor product in the competitor_prices table, using < ANY. Return product_id, name, price, ordered by price ascending. (The explanation tab also shows the ALL variant.)
| product_id | name | category | price |
|---|---|---|---|
| 1 | Model A Headphones | Audio | 12000 |
| 2 | Model B Headphones | Audio | 8500 |
| 3 | Model C Headphones | Audio | 15000 |
| 4 | Model D Headphones | Audio | 6000 |
| comp_id | name | category | price |
|---|---|---|---|
| 1 | Competitor X Headphones | Audio | 9000 |
| 2 | Competitor Y Headphones | Audio | 11000 |
| 3 | Competitor Z Headphones | Audio | 13500 |
Expected output (< ANY, price ascending):
| product_id | name | price |
|---|---|---|
| 4 | Model D Headphones | 6000 |
| 2 | Model B Headphones | 8500 |
| 1 | Model A Headphones | 12000 |
Note: Model C (15000) is higher than the competitors' maximum of 13500, so it is not cheaper than any competitor and is 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
Combining multiple EXISTS / NOT EXISTS predicates with AND enables precise row selection: a row satisfying condition A exists, while no row satisfying condition B exists. This is one of the most common patterns in practical behavior analysis and segment extraction.
-- Combine multiple EXISTS predicates with AND WHERE EXISTS ( -- ① a row satisfying condition A exists SELECT 1 FROM orders o1 WHERE o1.user_id = u.user_id AND o1.status = 'completed' ) AND NOT EXISTS ( -- ② no row satisfying condition B exists SELECT 1 FROM orders o2 WHERE o2.user_id = u.user_id AND o2.status = 'cancelled' )
From the users table, retrieve users on the 'premium' or 'standard' plan who have at least one completed order and no cancelled orders. Return user_id, name, plan, ordered by user_id ascending.
| user_id | name | plan |
|---|---|---|
| 1 | Taro Tanaka | premium |
| 2 | Hanako Sato | standard |
| 3 | Ichiro Suzuki | premium |
| 4 | Jiro Yamada | free |
| 5 | Saburo Ito | standard |
| order_id | user_id | status |
|---|---|---|
| 101 | 1 | completed |
| 102 | 1 | cancelled |
| 103 | 2 | completed |
| 104 | 3 | completed |
| 105 | 3 | pending |
| 106 | 5 | pending |
Expected output (user_id ascending):
| user_id | name | plan |
|---|---|---|
| 2 | Hanako Sato | standard |
| 3 | Ichiro Suzuki | premium |
Note: user 1 has a completed order but also a cancelled order → excluded. User 4 is on the free plan → excluded by IN. User 5 has no completed order (only pending) → EXISTS=FALSE and is 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