SQL String Functions: LOWER, UPPER, TRIM and Substrings

String functions transform, measure or extract text, allowing queries to clean labels and produce consistent display values without changing stored data.

Lesson 43 of 102Intermediate10 min read

String functions transform, measure or extract text, allowing queries to clean labels and produce consistent display values without changing stored data.

A name search and a cleaned report label may use the same text column differently. String functions let you state that transformation explicitly. Pay attention to characters, bytes and collation when a query must handle more than simple English text.

This reference adds detail to the main course. You can read it independently: the small database below supplies every table and row used in the examples. Start with the question each query answers, then compare the returned values with the data rather than memorising a line of syntax.

Set up the practice database

Run this setup once in a new practice database, before the examples. It uses four customers and six sales. Ana has two sales, Ben has one, Cara has two, and Dev has none.

Sale 106 has no customer link; sale 104 has an unknown amount. These deliberate test cases expose missing information and unmatched relationships.

SQL
CREATE TABLE customers (
  id INTEGER PRIMARY KEY,
  name VARCHAR(40) NOT NULL,
  city VARCHAR(40),
  manager_id INTEGER
);
CREATE TABLE sales (
  id INTEGER PRIMARY KEY,
  customer_id INTEGER,
  amount DECIMAL(10,2),
  status VARCHAR(20) NOT NULL,
  created_on DATE NOT NULL
);
INSERT INTO customers (id,name,city,manager_id) VALUES
  (1,'Ana','Leeds',NULL),(2,'Ben','Leeds',1),
  (3,'Cara','Porto',1),(4,'Dev',NULL,2);
INSERT INTO sales (id,customer_id,amount,status,created_on) VALUES
  (101,1,10,'paid','2026-01-01'),
  (102,1,30,'pending','2026-01-02'),
  (103,2,20,'paid','2026-01-02'),
  (104,3,NULL,'pending','2026-02-01'),
  (105,3,20,'paid','2026-02-02'),
  (106,NULL,5,'paid','2026-02-03');

An amount of zero would be a known value. The NULL amount here means the value is unknown. A customer with no matching sale differs from a sale whose customer_id is NULL.

The primary keys identify individual records even when amounts or cities repeat. Dates use year-month-day format. The examples specify sorting whenever order matters; insertion order alone does not guarantee display order.

How SQL string functions works

LOWER and UPPER change letter case, while TRIM removes unwanted characters at the edges of text. A common cleaning expression is LOWER(TRIM(city)), which first removes surrounding spaces and then normalises case. It does not remove interior spaces or automatically correct spelling. Keep the original value available during data cleaning so an unexpected transformation can be inspected before it is written back.

Length functions do not always measure the same thing. MySQL LENGTH measures bytes and CHAR_LENGTH measures characters. SQL Server LEN excludes trailing spaces, while DATALENGTH measures storage bytes. PostgreSQL char_length measures characters and octet_length measures bytes. SQLite length on ordinary text measures characters, with special behaviour around embedded zero characters. A string that contains a multibyte character can therefore have different byte and character lengths without any database error.

Substrings and positions

Substring functions extract part of a value using a start position and sometimes a length. Positions are commonly one-based, but the function names and accepted forms differ. SQLite substr(name,1,2), PostgreSQL substring(name FROM 1 FOR 2), MySQL SUBSTRING(name,1,2) and SQL Server SUBSTRING(name,1,2) all express the same simple prefix intent. Verify negative indexes and missing-length forms rather than assuming those extensions are shared.

Concatenation also varies. PostgreSQL and SQLite support the double-pipe operator, MySQL commonly uses CONCAT, and SQL Server offers CONCAT or a plus operator with different NULL rules. CONCAT may treat NULL arguments differently from a concatenation operator. Use COALESCE explicitly when a missing component should become a chosen label, and avoid silently erasing the distinction between absent and empty text. Applying a function to an indexed column can alter index usability; store or index an approved normalised expression when repeated searches justify it.

MySQL, PostgreSQL, SQL Server and SQLite

LOWER and UPPER are shared by all four systems, but Unicode case mapping and collations differ. SQLite’s built-in LOWER and UPPER normally handle ASCII letters unless additional extensions are used. TRIM syntax for removing a specific character set and concatenation NULL rules are not uniform; test those operations on the actual engine.

Check the engine-specific syntax and version requirements in SQLite scalar string functions, PostgreSQL string functions.

Practice task and worked solution

Return customer names in lower case and preserve their ids. Do not update the stored names.

Try the task before reading its worked solution. The supplied rows make the expected answer checkable by hand.

SQL
SELECT id,LOWER(name) AS name_key FROM customers ORDER BY id;
Output
id | name_key
1 | ana
2 | ben
3 | cara
4 | dev

Each selected expression produces a lower-case result value. The SELECT statement reads the table and adds the alias name_key to the output. Running a later SELECT name still returns the original capitalisation because this task contains no UPDATE.

Test UPPER('Ana'), LOWER('Ana') and TRIM(' Ana ') as independent expressions before combining them. Compare a multi-byte name’s byte and character measurements using the chosen engine’s documented functions. For SQLite, also test a non-ASCII case example to establish the default limitation. Keep that result separate from the ASCII sample, whose successful conversion proves only the simple case.

SQL String Functions: LOWER, UPPER, TRIM and Substrings Syntax

SQL string functions

SELECT id,UPPER(name) AS display_name,LOWER(city) AS city_key
FROM customers ORDER BY id;

SQL String Functions: LOWER, UPPER, TRIM and Substrings Summary

  • UPPER, LOWER and TRIM transform text in the result without changing stored data.
  • LOWER(TRIM(city)) builds a consistent comparison key from messy labels.
  • Substring positions start at 1, but function names differ: substr, SUBSTRING and SUBSTRING ... FROM ... FOR.
  • Length can mean characters or bytes: MySQL's LENGTH counts bytes and CHAR_LENGTH counts characters.
  • Unicode case handling differs by database; SQLite's built-in UPPER only changes ASCII letters.

SQL String Functions: LOWER, UPPER, TRIM and Substrings Examples

Each example shows the code, the output it produces and what each part does.

Example 1

Display names and city keys

The output expressions transform the saved values for this result only. LOWER leaves the missing city as NULL. The ids keep each row identifiable so you can compare original and transformed values rather than mistaking a display operation for a database update.

SQL
SELECT id,UPPER(name) AS display_name,LOWER(city) AS city_key
FROM customers ORDER BY id;
Output
id | display_name | city_key
1 | ANA | leeds
2 | BEN | leeds
3 | CARA | porto
4 | DEV | NULL

Common SQL String Functions: LOWER, UPPER, TRIM and Substrings Mistakes

Counting bytes instead of characters

Using MySQL LENGTH to validate a maximum character count can reject multibyte names even when they fit the required number of characters. Choose a character-count function for that policy. Also avoid treating LOWER as an accent-removal operation or assuming it performs identical Unicode folding everywhere.

SQL String Functions: LOWER, UPPER, TRIM and Substrings in Real Projects

Display labels and search keys in a pipeline

A reporting pipeline can expose an upper-case display label while retaining a lower-case search key and the original name. Keep these purposes separate. If a cleaning rule is later persisted with UPDATE, preview the transformed values and count affected rows before overwriting source text.

Retain original text beside cleaned text during a validation pass. Edge trimming, case normalisation and accent handling are separate policies and should not silently replace one another. Validate names by an appropriate character limit rather than assuming bytes equal characters, particularly when data crosses systems with different encodings or SQL Server text types.

SQL String Functions: LOWER, UPPER, TRIM and Substrings FAQ

Does TRIM remove every space?

No. Ordinary TRIM removes edge spaces, not interior whitespace, so ' a b ' becomes 'a b'. To collapse repeated inner spaces, use REPLACE repeatedly or a regular expression function such as PostgreSQL's regexp_replace(name, '\s+', ' ', 'g').

Are bytes and characters the same?

Not for many encodings. In UTF-8, é takes two bytes and an emoji takes four, so a byte count is larger than the character count. Pick the measurement that matches the application rule: characters for "at most 40 letters", bytes for storage limits.

Does LOWER make every international search case-insensitive?

No. Unicode mapping and collation support differ: SQLite's built-in LOWER leaves É unchanged, and some languages have special rules, such as Turkish dotted and dotless i. Test representative user names and use a documented search policy, ideally with a case-insensitive collation.

How do I find the position of text inside a string?

Use INSTR(text, 'e') in SQLite and MySQL, POSITION('e' IN text) or STRPOS(text, 'e') in PostgreSQL, and CHARINDEX('e', text) in SQL Server. All return 1 for the first character and 0 when the text isn't found, so INSTR('Leeds', 'e') is 2.

How do I split a string into parts in SQL?

PostgreSQL has split_part(text, ',', 2) and string_to_array, SQL Server has STRING_SPLIT, and MySQL has SUBSTRING_INDEX. Needing to split stored text often signals that the values belong in separate rows of a related table, which makes filtering and joining far easier.

SQL String Functions: LOWER, UPPER, TRIM and Substrings Exercises

Answer each one and check it instantly. If you get stuck, open the hint before the answer.

Multiple choicemedium

What city_key is returned for Dev by LOWER(city)?

SQL String Functions: LOWER, UPPER, TRIM and Substrings Quiz

2 questions to check what you learned.

  1. Does SELECT UPPER(name) alter saved names?

    • Yes, it permanently replaces the stored names
    • No, it transforms values in the query result
    • Yes, but only names already containing lowercase letters
  2. What does MySQL LENGTH measure?

    • Characters including every trailing space
    • Only ASCII letters rather than bytes
    • Bytes rather than the character count