Lesson 13: Numeric, Conversion, and Conditional Functions
In Lesson 12, we learned string functions. Beyond dates and strings, SQL also has math functions for numbers, conversion functions to change data types, and conditional functions to select values based on conditions. Learning all three at once greatly increases the expressiveness of your queries.
Already familiar?
If you're comfortable with ROUND, ABS, CAST, NULLIF, and GREATEST/LEAST, skip ahead to Lesson 14: UNION.
Math Functions
ROUND -- Rounding
ROUND(value, digits) rounds to the specified number of decimal places. We used it briefly in Lesson 4, but here we cover it systematically.
-- Average price at various decimal places
SELECT
ROUND(AVG(price), 2) AS avg_2dp,
ROUND(AVG(price), 0) AS avg_int,
ROUND(AVG(price), -3) AS avg_1000
FROM products
WHERE is_active = 1;
Result (example):
| avg_2dp | avg_int | avg_1000 |
|---|---|---|
| 659594.5 | 659594.0 | 659594.0 |
ROUND(value, -3)rounds to the nearest thousand. Useful when displaying approximate values in reports.
ABS -- Absolute Value
-- Difference between cost and selling price (prevent negatives)
SELECT
name,
price,
cost_price,
ABS(price - cost_price) AS margin
FROM products
WHERE is_active = 1
ORDER BY margin DESC
LIMIT 5;
CEIL / FLOOR -- Ceiling and Floor
SQLite does not have CEIL/FLOOR. Use CAST and CASE as substitutes.
MOD -- Remainder
-- Extract even-ID customers only (A/B test group splitting)
SELECT id, name, grade
FROM customers
WHERE MOD(id, 2) = 0
AND is_active = 1
LIMIT 10;
In SQLite, use the
a % boperator instead ofMOD(a, b).
RANDOM -- Random Sampling
Warning:
ORDER BY RANDOM()sorts all rows, so it's slow on large tables. Use alternative sampling techniques in production.
Type Conversion Functions
CAST -- Type Conversion
CAST(expression AS type) explicitly converts data types. We already used CAST(SUBSTR(...) AS INTEGER) in Lesson 12.
-- String -> Number
SELECT CAST('12345' AS INTEGER) AS num_val;
-- Number -> String (for concatenation)
SELECT 'Order #' || CAST(id AS TEXT) AS label
FROM orders
LIMIT 3;
Integer Division Pitfall
We covered this in Lesson 4, but it's the most common conversion mistake, so it's worth emphasizing again.
-- Integer / Integer = Integer (decimals truncated!)
SELECT 7 / 2 AS wrong; -- 3 (not 3.5!)
-- Solution: Convert one side to float
SELECT 7 / 2.0 AS correct; -- 3.5
SELECT CAST(7 AS REAL) / 2 AS also; -- 3.5
SELECT 7 * 1.0 / 2 AS trick; -- 3.5
-- Practical: Cancellation rate vs total orders
SELECT
COUNT(*) AS total_orders,
SUM(CASE WHEN status = 'cancelled' THEN 1 ELSE 0 END) AS cancelled,
ROUND(
SUM(CASE WHEN status = 'cancelled' THEN 1 ELSE 0 END) * 100.0 / COUNT(*),
1
) AS cancel_rate_pct
FROM orders;
Conditional Functions
NULLIF -- Preventing Division by Zero
NULLIF(a, b) -- returns NULL if a equals b, otherwise returns a. Most commonly used to prevent division-by-zero errors.
-- Prevent division by zero
SELECT
category_id,
SUM(CASE WHEN is_active = 1 THEN 1 ELSE 0 END) AS active_count,
SUM(CASE WHEN is_active = 0 THEN 1 ELSE 0 END) AS inactive_count,
ROUND(
SUM(CASE WHEN is_active = 1 THEN 1 ELSE 0 END) * 100.0
/ NULLIF(SUM(CASE WHEN is_active = 0 THEN 1 ELSE 0 END), 0),
1
) AS active_to_inactive_ratio
FROM products
GROUP BY category_id
LIMIT 5;
NULLIF(denominator, 0)-- if the denominator is 0, returns NULL so you get NULL instead of an error.
IIF / IF -- Simple Conditional Branching
A shorthand for CASE expressions. Can be written concisely when there is only one condition.
GREATEST / LEAST -- Max/Min Among Multiple Values
Used to compare values across multiple columns within a row. MAX/MIN aggregate across rows, while GREATEST/LEAST compare across columns.
SQLite does not have GREATEST/LEAST. MAX()/MIN() serve the same purpose.
MAX vs GREATEST:
MAX(col)finds the maximum across multiple rows, whileGREATEST(a, b, c)finds the maximum among multiple values within a single row.
Summary
| Concept | Description | Example |
|---|---|---|
| ROUND | Rounding (negative digits supported) | ROUND(price, -3) |
| ABS | Absolute value | ABS(price - cost_price) |
| CEIL / FLOOR | Ceiling / Floor | CEIL(4.2) → 5 |
| MOD (%) | Remainder | MOD(id, 2) = 짝수 필터 |
| RANDOM | Random ordering | ORDER BY RANDOM() |
| CAST | Type conversion | CAST('123' AS INTEGER) |
| TYPEOF | Type check (SQLite) | TYPEOF(price) |
| Integer division | integer/integer=integer pitfall | * 1.0으로 실수 변환 |
| NULLIF | NULL if equal | NULLIF(분모, 0) |
| IIF / IF | Simple conditional branching | IIF(cond, true, false) |
| GREATEST / LEAST | Max/min across columns | GREATEST(a, b, c) |
Lesson Review Problems
These are simple problems to immediately test the concepts from this lesson. For comprehensive practice combining multiple concepts, see the Practice Problems section.
Practice Problems
Problem 1
Display the average, maximum, and minimum prices of active products, each rounded to the nearest thousand. Return avg_price, max_price, min_price.
Answer
Problem 2
Calculate the margin (difference between selling price and cost price) as an absolute value. Return name, price, cost_price, margin, sorted by margin descending, limited to 10 rows.
Answer
Problem 3
Extract only odd-ID customers and return id, name, grade. Target only active customers, limited to 10 rows.
Problem 4
Randomly extract 3 active products and return name and price.
Answer
Problem 5
Convert the last 5-digit sequence number from order_number to an integer, and convert the order amount to a string with '₩' prefix. Return order_number, seq_no (integer), amount_display (string), limited to 5 rows.
Answer
Problem 6
Calculate the cancellation rate relative to total orders. Avoid the integer division pitfall and display to 1 decimal place. Return total_orders, cancelled_orders, cancel_rate_pct.
Answer
Problem 7
Calculate the active product ratio per category, using NULLIF to prevent division-by-zero errors in categories with 0 inactive products. Return category_id, active_count, inactive_count, ratio.
Answer
SELECT
category_id,
SUM(CASE WHEN is_active = 1 THEN 1 ELSE 0 END) AS active_count,
SUM(CASE WHEN is_active = 0 THEN 1 ELSE 0 END) AS inactive_count,
ROUND(
SUM(CASE WHEN is_active = 1 THEN 1 ELSE 0 END) * 1.0
/ NULLIF(SUM(CASE WHEN is_active = 0 THEN 1 ELSE 0 END), 0),
2
) AS ratio
FROM products
GROUP BY category_id;
Problem 8
Classify product prices as 'premium' if 1,000,000 or more, otherwise 'standard'. Use IIF (SQLite) or IF (MySQL). Return name, price, tier, sorted by price descending, limited to 10 rows.
Answer
Problem 9
Cap order amounts: if below 500,000, set to 500,000; if above 5,000,000, set to 5,000,000. Return order_number, total_amount, capped_amount, limited to 10 rows.
Answer
Problem 10
Calculate margin rate per product ((price - cost_price) / price * 100), handling products with a price of 0 to prevent errors. Return name, price, cost_price, margin_pct (1 decimal place), sorted by margin rate descending, limited to 10 rows.
Answer
Scoring Guide
| Score | Next Step |
|---|---|
| 9-10 | Move on to Lesson 14: UNION |
| 7-8 | Review the explanations for incorrect answers, then proceed |
| Half or fewer | Re-read this lesson |
| 3 or fewer | Start again from Lesson 12: String Functions |
Problem Areas:
| Area | Problems |
|---|---|
| ROUND (rounding) | 1 |
| ABS (absolute value) | 2 |
| MOD (remainder) | 3 |
| RANDOM (random) | 4 |
| CAST (type conversion) | 5 |
| Integer division pitfall | 6 |
| NULLIF (prevent divide by zero) | 7, 10 |
| IIF / IF (simple conditional) | 8 |
| GREATEST / LEAST (cross-column comparison) | 9 |
Next: Lesson 14: UNION