Functions for text and numbers
A function takes a value, does something to it and gives back a new value. UPPER('asha') gives 'ASHA'. SQL has functions for text, for numbers and for dates. This lesson covers the text and number functions that you will use every week. The functions here work on one row at a time. The next lesson covers a different family that works on many rows at once.
Changing case
SELECT name, UPPER(name) AS capitals, LOWER(name) AS small
FROM customers
LIMIT 4;Result
| name | capitals | small |
|---|---|---|
| Asha Verma | ASHA VERMA | asha verma |
| Ravi Kumar | RAVI KUMAR | ravi kumar |
| Meena Gill | MEENA GILL | meena gill |
| Kabir Khan | KABIR KHAN | kabir khan |
4 rows
The table is not changed. Functions in a SELECT change only what is shown.
Comparing without caring about case
In lesson 3, searching for 'delhi' found nothing because the table says 'Delhi'. Turn the column to small letters before comparing, and the search works however the text was typed.
SELECT name, city
FROM customers
WHERE LOWER(city) = 'delhi';Result
| name | city |
|---|---|
| Ravi Kumar | Delhi |
| Imran Ali | Delhi |
2 rows
This is the standard way to make a comparison ignore case in any database.
Length
SELECT name, LENGTH(name) AS letters
FROM products
ORDER BY letters DESC
LIMIT 3;Result
| name | letters |
|---|---|
| Ball Pen pack of 10 | 19 |
| Pressure Cooker 3 L | 19 |
| Notebook 200 pages | 18 |
3 rows
LENGTH counts characters, including spaces. In SQL Server the function is called LEN.
Removing spaces at the ends
Data typed by people often has stray spaces, and 'Delhi ' with a space does not equal 'Delhi'. TRIM removes spaces from both ends. LTRIM and RTRIM do one side.
SELECT '[' || TRIM(' Delhi ') || ']' AS trimmed,
LENGTH(' Delhi ') AS before,
LENGTH(TRIM(' Delhi ')) AS after;Result
| trimmed | before | after |
|---|---|---|
| [Delhi] | 10 | 5 |
1 row
Part of a text
SUBSTR(text, start, length) cuts a piece out. Positions start at 1, not 0.
SELECT order_date,
SUBSTR(order_date, 1, 4) AS year,
SUBSTR(order_date, 6, 2) AS month
FROM orders
LIMIT 3;Result
| order_date | year | month |
|---|---|---|
| 2026-01-05 | 2026 | 01 |
| 2026-01-12 | 2026 | 01 |
| 2026-01-20 | 2026 | 01 |
3 rows
Leave out the length to take everything from the start position to the end. MySQL and PostgreSQL accept SUBSTR too, and also SUBSTRING. SQL Server has only SUBSTRING.
Replace
REPLACE(text, find, put) swaps every occurrence of one piece of text for another.
SELECT name, REPLACE(name, ' kg', ' kilogram') AS long_name
FROM products
WHERE name LIKE '% kg';Result
| name | long_name |
|---|---|
| Basmati Rice 5 kg | Basmati Rice 5 kilogram |
| Toor Dal 1 kg | Toor Dal 1 kilogram |
2 rows
Finding where something is
INSTR(text, piece) gives the position of the first match, or 0 if there is none. Combined with SUBSTR, it splits text at a marker. This takes the first name from a full name by cutting at the space.
SELECT name,
SUBSTR(name, 1, INSTR(name, ' ') - 1) AS first_name
FROM employees
LIMIT 4;Result
| name | first_name |
|---|---|
| Anita Kapoor | Anita |
| Rohit Bansal | Rohit |
| Deepa Iyer | Deepa |
| Manoj Yadav | Manoj |
4 rows
INSTR exists in SQLite, MySQL and Oracle. PostgreSQL uses POSITION(piece IN text) and SQL Server uses CHARINDEX(piece, text).
Rounding
ROUND(number, places) rounds to the number of decimal places you give. With no second value it rounds to a whole number.
SELECT name, price,
price * 1.18 AS exact,
ROUND(price * 1.18, 2) AS two_places,
ROUND(price * 1.18) AS whole
FROM products
LIMIT 4;Result
| name | price | exact | two_places | whole |
|---|---|---|---|---|
| Basmati Rice 5 kg | 650 | 767.0 | 767.0 | 767.0 |
| Toor Dal 1 kg | 160 | 188.79999999999998 | 188.8 | 189.0 |
| Sunflower Oil 1 L | 145 | 171.1 | 171.1 | 171.0 |
| Tea 500 g | 280 | 330.4 | 330.4 | 330.0 |
4 rows
Always round money for display. Unrounded results of multiplication and division often carry a long tail of digits.
Other number functions
SELECT ABS(-250) AS size,
10 % 3 AS remainder,
MAX(3, 9, 5) AS largest,
MIN(3, 9, 5) AS smallest;Result
| size | remainder | largest | smallest |
|---|---|---|---|
| 250 | 1 | 9 | 3 |
1 row
ABS removes the minus sign. % gives the remainder after division; some databases write it MOD(10, 3). Using MAX and MIN with several values in one row, as here, is a SQLite feature. MySQL and PostgreSQL call those GREATEST and LEAST.
Changing the type with CAST
Sometimes a number is stored as text, or you want a whole number treated as a decimal. CAST(value AS type) converts.
SELECT CAST('42' AS INTEGER) + 1 AS number,
CAST(7 AS REAL) / 2 AS half,
CAST(SUBSTR('2026-03-15', 1, 4) AS INTEGER) AS year;Result
| number | half | year |
|---|---|---|
| 43 | 3.5 | 2026 |
1 row
The middle column is the tidy cure for the whole-number division trap from lesson 2.
Functions inside functions
The result of one function can be handed to another. Read from the inside out.
SELECT name,
UPPER(SUBSTR(name, 1, 3)) AS code
FROM products
LIMIT 4;Result
| name | code |
|---|---|
| Basmati Rice 5 kg | BAS |
| Toor Dal 1 kg | TOO |
| Sunflower Oil 1 L | SUN |
| Tea 500 g | TEA |
4 rows
SUBSTR takes the first three letters and UPPER turns them into capitals.
Functions in WHERE and ORDER BY
A function can be used anywhere a value can.
SELECT name
FROM customers
WHERE LENGTH(name) > 10
ORDER BY LENGTH(name) DESC;Result
| name |
|---|
| Arjun Mehta |
1 row
One caution for large tables: wrapping a column in a function inside WHERE usually stops the database from using an index on that column, so the search reads every row. On small tables it does not matter.
Names differ between databases
Function names are the least standard part of SQL. The ideas are the same everywhere, and the spelling is not.
| Job | SQLite | MySQL | PostgreSQL | SQL Server |
|---|---|---|---|---|
| Length | LENGTH | CHAR_LENGTH | LENGTH | LEN |
| Part of text | SUBSTR | SUBSTRING | SUBSTRING | SUBSTRING |
| Join text | || | CONCAT | || | + or CONCAT |
| Find position | INSTR | INSTR | POSITION | CHARINDEX |
| If null | COALESCE | COALESCE | COALESCE | COALESCE |
When a function from one product fails in another, search that product's manual for the job you want. The equivalent nearly always exists.
Try it yourself
Exercise 1. Show each customer's name in capital letters.
Show one answer
SELECT UPPER(name) FROM customers;| UPPER(name) |
|---|
| ASHA VERMA |
| RAVI KUMAR |
| MEENA GILL |
| KABIR KHAN |
| SUNITA RAO |
| ARJUN MEHTA |
| PRIYA NAIR |
| IMRAN ALI |
| NEHA JOSHI |
| TARA SINGH |
| VIKRAM DAS |
| JOY THOMAS |
12 rows
Exercise 2. Show each product's name and its price with a 10 percent discount, rounded to a whole number. Name the column sale_price.
Show one answer
SELECT name, ROUND(price * 0.9) AS sale_price FROM products;| name | sale_price |
|---|---|
| Basmati Rice 5 kg | 585.0 |
| Toor Dal 1 kg | 144.0 |
| Sunflower Oil 1 L | 131.0 |
| Tea 500 g | 252.0 |
| Notebook 200 pages | 54.0 |
| Ball Pen pack of 10 | 81.0 |
| Geometry Box | 108.0 |
| School Bag | 675.0 |
| LED Bulb 9 W | 99.0 |
| Extension Board | 359.0 |
| Earphones | 449.0 |
| Power Bank | 1169.0 |
16 rows
Showing the first 12 of 16 rows.
Exercise 3. Show the name and the year of joining (the first four characters of joined) for every customer. Name the second column year.
Show one answer
SELECT name, SUBSTR(joined, 1, 4) AS year FROM customers;| name | year |
|---|---|
| Asha Verma | 2025 |
| Ravi Kumar | 2025 |
| Meena Gill | 2025 |
| Kabir Khan | 2025 |
| Sunita Rao | 2025 |
| Arjun Mehta | 2025 |
| Priya Nair | 2025 |
| Imran Ali | 2025 |
| Neha Joshi | 2025 |
| Tara Singh | 2025 |
| Vikram Das | 2025 |
| Joy Thomas | 2026 |
12 rows
Examples on this page were run with SQLite 3.50.4 on 12 November 2026. The results shown are the real results.
This is an independent learning site. It is not connected with the makers of any database product. MySQL, PostgreSQL, SQL Server, Oracle and SQLite are named only so that you know where a piece of SQL works. The shop, its customers and its staff in the practice database are made up.