Skip to content

Beginner: asking questions · Functions, CASE and NULL · topic 11 of 62 · 35 min

Text functions

Explanation

Text functions change or take apart text inside a query: UPPER and LOWER change case, LENGTH counts characters, TRIM removes spaces, SUBSTR cuts out a piece, INSTR finds where a character is, REPLACE swaps text and || joins text. Together they clean messy names and emails and pull out parts such as an email domain.

Why do text functions matter?

Real data is typed by people, and people are not consistent. One customer writes "meena joshi", another "ANIL MEHRA", a third adds a space before the email. If you compare such values directly, "Pune" and " pune" look different, and a report counts them as two cities. Text functions let you clean and reshape text inside the query, without changing what is stored.

A function is a named tool that takes some inputs (called arguments) in brackets and gives back one value. UPPER(name) takes a name and gives it back in capital letters. In a SELECT, the function runs once for every row.

The everyday text functions

FunctionWhat it doesExampleResult
UPPER(x), LOWER(x)Change to capital or small lettersUPPER('pune')PUNE
LENGTH(x)Number of charactersLENGTH('Asha Verma')10
TRIM(x)Remove spaces at both ends (LTRIM, RTRIM: one end)TRIM(' Rohan Das ')Rohan Das
SUBSTR(x, start, n)Cut n characters starting at position start (the first character is 1)SUBSTR('Basmati Rice 5kg', 1, 7)Basmati
SUBSTR(x, start)Everything from start to the endSUBSTR('Basmati Rice 5kg', 9)Rice 5kg
INSTR(x, find)Position of the first find, or 0 if missingINSTR('Asha Verma', ' ')5
REPLACE(x, old, new)Swap every old for newREPLACE('98450-12345', '-', '')9845012345
a || bJoin (concatenate) text'Asha' || ' ' || 'Verma'Asha Verma

Positions in SQL start at 1, not 0 as in Python or JavaScript. SUBSTR(x, 1, 3) means "the first three characters".

Combining functions: first name and email domain

Functions can be put inside each other; the inner one runs first. To get a first name, find the space with INSTR and take everything before it. To get an email domain, find the @ and take everything after it.

sql
SELECT name, SUBSTR(name, 1, INSTR(name, ' ') - 1) AS first_name
FROM customers;
-- Asha Verma | Asha
-- Ravi Kumar | Ravi   ... 6 rows
INSTR finds the space at position 5; SUBSTR takes 5 − 1 = 4 characters.
sql
SELECT id, SUBSTR(email, INSTR(email, '@') + 1) AS domain
FROM signups WHERE email IS NOT NULL;
-- 2 | yahoo.co.in
-- 4 | rediffmail.com   ... (row 1 still has a capital G and a trailing space)
Start one character after the @ and take the rest.

Cleaning messy input

The usual cleaning recipe for an email is LOWER(TRIM(email)): remove stray spaces, then make it all small letters, because email addresses are compared without case in practice. For phone numbers, strip dashes and spaces with REPLACE, nested twice.

sql
SELECT id, LOWER(TRIM(email)) AS clean_email,
       REPLACE(REPLACE(phone, '-', ''), ' ', '') AS phone_digits
FROM signups;
-- 1 | rohan.das@gmail.com | 9845012345
-- 3 | anil@outlook.com    | 9123456789
-- 5 | NULL                | 9000011111
Text functions given NULL return NULL, so Tenzin's missing email stays missing.
Tip: To compare text without worrying about case, compare cleaned versions: WHERE LOWER(TRIM(city)) = 'pune'. Better still, clean the data once when it is saved (module 8) so every query does not have to.

|| and CONCAT in different databases

|| is the SQL standard way to join text, and SQLite, PostgreSQL and Oracle use it. MySQL treats || as OR unless a setting is changed, so MySQL code uses CONCAT('Asha', ' ', 'Verma'). SQL Server joins text with + or CONCAT. SQLite 3.44 and later also has concat().

Careful: NULL behaves differently. In SQLite and PostgreSQL, 'Asha' || NULL is NULL, so one missing piece blanks the whole result. CONCAT is kinder: concat('Asha', NULL) gives 'Asha' in SQLite, PostgreSQL and SQL Server. MySQL's CONCAT is the exception: it returns NULL if any argument is NULL. Topic 5 shows COALESCE, which fixes this everywhere.
TaskSQLitePostgreSQLMySQLSQL Server
Find a characterINSTR(s, '@')POSITION('@' IN s) or STRPOS(s, '@')INSTR(s, '@')CHARINDEX('@', s)
Number of charactersLENGTH(s)LENGTH(s)CHAR_LENGTH(s) (LENGTH counts bytes)LEN(s)
Part of textSUBSTR(s, 2, 3)SUBSTR(s, 2, 3)SUBSTR(s, 2, 3)SUBSTRING(s, 2, 3)

Common mistakes

  • A name with no space: INSTR returns 0, so SUBSTR(name, 1, 0 − 1) gives an empty text. Check with CASE (topic 4) when single names are possible.
  • Counting from 0. SQL positions start at 1, so SUBSTR(x, 0, 3) is not the first three characters. Use SUBSTR(x, 1, 3).
  • Forgetting TRIM before comparing. ' Pune' = 'Pune' is false. Clean both sides.
  • Using LENGTH in MySQL for Hindi or other non-English text: it counts bytes, not letters. Use CHAR_LENGTH there.
  • Joining with || when a piece can be NULL, and getting NULL for the whole value. Wrap the piece in COALESCE.

Need help?

Stuck on a word or an idea? Search this course, or every course, and jump straight to the explanation or a worked question.

Try:

Watch the lesson

Text functions · 1/7

Text functions

Data typed by people is messy: extra spaces, capital letters in odd places, dashes in phone numbers. Text functions clean it inside the query.

Prefer a video by a teacher? Find free videos on “sql string functions substr instr trim upper lower replace concat tutorial” on YouTube ↗

In real life: Cleaning a sign-up list before an SMS and email campaign

A coaching institute collects leads from a web form, a walk-in register and a partner's spreadsheet. Before sending reminders, its analyst cleans the list in SQL: trims spaces, lower-cases emails, strips dashes from mobile numbers, and pulls out the email domain to see how many leads use each provider. Doing it in one query means the same cleaning is applied every time the list is refreshed.

sql
SELECT id,
       TRIM(full_name)                              AS name,
       LOWER(TRIM(email))                           AS email,
       REPLACE(REPLACE(phone, '-', ''), ' ', '')    AS mobile
FROM signups;
Row 1 becomes: 1 | Rohan Das | rohan.das@gmail.com | 9845012345.

Practice (0/4 done)

Task 1 · Code · SQL

Make a short city code. From customers, return name and the first 3 letters of city in capital letters, named city_code (for example PUN for Pune).

Task 2 · Code · SQL

From customers, return name and the first name (everything before the first space), named first_name. Use SUBSTR and INSTR.

Task 3 · Code · SQL

The signups table has messy emails. Return id and the email with spaces removed from both ends and in small letters, named clean_email. Keep every row (a missing email stays NULL).

Task 4 · Code · SQL

Which email providers do the sign-ups use? For rows that have an email, return id and the domain (the part after @), trimmed and in small letters, named domain.

Quick quiz

Question 1

1.What does SUBSTR('Steel Tiffin Box', 7, 6) return?

Question 2

2.In SQLite, what is 'Asha' || NULL?

Question 3

3.You are writing for MySQL with its default settings. How do you join first_name and last_name with a space?

Question 4

4.Why might WHERE city = 'Pune' miss a row whose city looks like Pune on screen?

Question 5

5.What does INSTR('Madonna', ' ') return?

Read more (free)

Open a question to see the answer and why. The first ones are this topic's own quiz, so try the quiz above before you peek.

What does SUBSTR('Steel Tiffin Box', 7, 6) return?

Answer: Tiffin

Position 7 is the T of Tiffin (positions start at 1), and 6 characters gives Tiffin.

In SQLite, what is 'Asha' || NULL?

Answer: NULL

Joining with || and a NULL gives NULL. Use COALESCE or concat() if a piece may be missing.

You are writing for MySQL with its default settings. How do you join first_name and last_name with a space?

Answer: CONCAT(first_name, ' ', last_name)

MySQL reads || as OR by default; CONCAT is the safe choice there.

Why might WHERE city = 'Pune' miss a row whose city looks like Pune on screen?

Answer: Because the stored value may have a hidden space or different case, such as ' Pune' or 'PUNE'

Clean both sides with TRIM and LOWER, or clean the data when it is saved.

What does INSTR('Madonna', ' ') return?

Answer: 0

INSTR returns 0 when the text is not found, so a SUBSTR built on it gives an empty first name.

After s = " hi " and then s.strip() on its own line, what is s?Related

Answer: " hi "

Strings are immutable. s.strip() made a new string that was never stored, so s is unchanged.

From String processing

What is "PYTHON"[0]?Related

Answer: "P"

Indexes start at 0, so index 0 is the first character, P.

From Strings: working with text

GROUP_CONCAT(name) without ORDER BY: in what order are the names?Related

Answer: Not guaranteed; add ORDER BY inside the aggregate

Only ORDER BY inside the aggregate fixes the order.

From Conditional aggregation and string aggregation

"Bengaluru".substring(3, 6) is…Related

Answer: "gal"

Indexes 3, 4, 5: g, a, l.

From Strings in depth

Pass the quiz (60% or more) or mark this topic as done when you are ready.

Your progress is saved on this device only.

Next steps

  1. 4 more topics in “Functions, CASE and NULL” before its exam: Numbers and maths, Working with dates, CASE expressions, NULL: the missing value.
  2. Module 3 exam: Functions, CASE and NULL · 15 questions · 25 min, without help. 5 topics of this module still to finish first.
  3. Then the next module, Aggregation: GROUP BY and HAVING. 62 topics left in the course before the final exam.

← Previous: DISTINCT and how a query runs