Over 30 built-in scalar functions are available for string manipulation, math, and conditional logic. This tutorial walks through the most useful ones with a product catalog dataset. Every function runs in the block-oriented executor—35% faster than PostgreSQL on the scalar_functions benchmark.
CREATE TABLE products (
id SERIAL PRIMARY KEY,
name TEXT NOT NULL,
sku TEXT NOT NULL,
price FLOAT NOT NULL,
discount FLOAT,
category TEXT,
notes TEXT
);
INSERT INTO products (name, sku, price, discount, category, notes) VALUES
('Wireless Mouse', 'WM-2024-PRO', 49.99, 0.10, 'Electronics', 'Best seller'),
('USB-C Hub', 'HUB-7PORT', 34.50, NULL, 'Electronics', 'New arrival'),
('Standing Desk', 'DESK-ADJ-60', 599.00, 0.15, 'Furniture', NULL),
('Ergonomic Chair', 'CHAIR-ERG-V2', 449.99, 0.20, 'Furniture', 'Updated model'),
('Mechanical Keyboard','KB-MX-BLUE', 89.95, 0.05, 'Electronics', 'Cherry MX Blue'),
('Monitor Arm', 'ARM-DUAL-27', 129.00, NULL, 'Accessories', NULL),
('Desk Lamp', 'LAMP-LED-DIM', 45.00, 0.10, 'Accessories', 'Dimmable LED');
UPPER, LOWER, and LENGTH are the
workhorses of string processing. Use them for normalization, display
formatting, and validation.
SELECT name,
UPPER(name) AS upper_name,
LOWER(sku) AS lower_sku,
LENGTH(name) AS name_len
FROM products
WHERE LENGTH(name) > 10
ORDER BY name_len DESC;
Result
| name | upper_name | lower_sku | name_len |
|---|---|---|---|
| Mechanical Keyboard | MECHANICAL KEYBOARD | kb-mx-blue | 19 |
| Ergonomic Chair | ERGONOMIC CHAIR | chair-erg-v2 | 15 |
| Wireless Mouse | WIRELESS MOUSE | wm-2024-pro | 14 |
| Standing Desk | STANDING DESK | desk-adj-60 | 13 |
| Monitor Arm | MONITOR ARM | arm-dual-27 | 11 |
SUBSTRING(str FROM start FOR length) extracts a portion.
REPLACE(str, from, to) swaps substrings.
SELECT sku,
SUBSTRING(sku FROM 1 FOR 3)
AS prefix,
REPLACE(sku, '-', '/')
AS slash_sku
FROM products
ORDER BY sku;
Result
| sku | prefix | slash_sku |
|---|---|---|
| ARM-DUAL-27 | ARM | ARM/DUAL/27 |
| CHAIR-ERG-V2 | CHA | CHAIR/ERG/V2 |
| DESK-ADJ-60 | DES | DESK/ADJ/60 |
| HUB-7PORT | HUB | HUB/7PORT |
| KB-MX-BLUE | KB- | KB/MX/BLUE |
| LAMP-LED-DIM | LAM | LAMP/LED/DIM |
| WM-2024-PRO | WM- | WM/2024/PRO |
CONCAT(a, b, ...) joins strings together. Unlike the
|| operator, CONCAT treats NULL
as an empty string.
SELECT name,
CONCAT(category, ': ', name)
AS full_label
FROM products
ORDER BY category, name;
Result
| name | full_label |
|---|---|
| Desk Lamp | Accessories: Desk Lamp |
| Monitor Arm | Accessories: Monitor Arm |
| Mechanical Keyboard | Electronics: Mechanical Keyboard |
| USB-C Hub | Electronics: USB-C Hub |
| Wireless Mouse | Electronics: Wireless Mouse |
| Ergonomic Chair | Furniture: Ergonomic Chair |
| Standing Desk | Furniture: Standing Desk |
Compute discounted prices with ROUND, use ABS
for absolute values, and MOD for modular arithmetic.
SELECT name, price,
COALESCE(discount, 0) AS disc,
ROUND(price * (1 - COALESCE(
discount, 0))::numeric, 2)
AS sale_price,
ABS(price - 100) AS dist_from_100,
MOD(id, 3) AS group_num
FROM products
ORDER BY sale_price DESC;
Result
| name | price | disc | sale_price | dist_from_100 | group_num |
|---|---|---|---|---|---|
| Standing Desk | 599 | 0.15 | 509.15 | 499 | 0 |
| Ergonomic Chair | 449.99 | 0.2 | 359.99 | 349.99 | 1 |
| Monitor Arm | 129 | 0 | 129 | 29 | 0 |
| Mechanical Keyboard | 89.95 | 0.05 | 85.45 | 10.05 | 2 |
| Wireless Mouse | 49.99 | 0.1 | 44.99 | 50.01 | 1 |
| Desk Lamp | 45 | 0.1 | 40.5 | 55 | 1 |
| USB-C Hub | 34.5 | 0 | 34.5 | 65.5 | 2 |
COALESCE(a, b, ...) returns the first non-NULL argument.
NULLIF(a, b) returns NULL if a = b, otherwise
returns a. Together they handle missing data gracefully.
SELECT name,
COALESCE(notes, 'No notes')
AS display_notes,
COALESCE(discount, 0) * 100
AS disc_pct,
NULLIF(category, 'Electronics')
AS non_elec_cat
FROM products
ORDER BY name;
Result
| name | display_notes | disc_pct | non_elec_cat |
|---|---|---|---|
| Desk Lamp | Dimmable LED | 10 | Accessories |
| Ergonomic Chair | Updated model | 20 | Furniture |
| Mechanical Keyboard | Cherry MX Blue | 5 | NULL |
| Monitor Arm | No notes | 0 | Accessories |
| Standing Desk | No notes | 15 | Furniture |
| USB-C Hub | New arrival | 0 | NULL |
| Wireless Mouse | Best seller | 10 | NULL |
CASE WHEN is SQL’s if/else. Use it to categorize,
bucket, or transform values conditionally.
SELECT name, price,
CASE
WHEN price >= 400 THEN 'premium'
WHEN price >= 80 THEN 'mid-range'
ELSE 'budget'
END AS tier,
CASE
WHEN discount IS NULL THEN 'full price'
WHEN discount >= 0.15 THEN 'big sale'
ELSE 'small discount'
END AS pricing
FROM products
ORDER BY price DESC;
Result
| name | price | tier | pricing |
|---|---|---|---|
| Standing Desk | 599 | premium | big sale |
| Ergonomic Chair | 449.99 | premium | big sale |
| Monitor Arm | 129 | mid-range | full price |
| Mechanical Keyboard | 89.95 | mid-range | small discount |
| Wireless Mouse | 49.99 | budget | small discount |
| Desk Lamp | 45 | budget | small discount |
| USB-C Hub | 34.5 | budget | full price |
In this tutorial you transformed a 7-product catalog using 12 scalar functions and conditional expressions:
UPPER / LOWER for case normalizationLENGTH for string measurement and filteringSUBSTRING for extracting portions of stringsREPLACE for find-and-replace within stringsCONCAT for NULL-safe string joiningABS / ROUND / MOD for numeric computationCOALESCE for default values on NULLsNULLIF for conditional NULL generationCASE WHEN for inline conditional logic