Post

String Functions (UPPER, LOWER)

String Functions (UPPER, LOWER)

title: “String Functions (UPPER, LOWER)” part: 1 topic_number: 20 slug: “string-functions-upper-lower” difficulty: “Beginner” prerequisites: “select-from-where” —

String Functions (UPPER, LOWER)

What Is It?

String functions manipulate text data. UPPER() converts text to uppercase, LOWER() converts to lowercase. They’re perfect for normalizing data, making case-insensitive comparisons, and formatting output.

Real-world analogy: Like the “Caps Lock” key — UPPER() turns everything to capitals, LOWER() turns everything to lowercase.


Basic Syntax

1
2
UPPER(column_or_string)  -- Converts to UPPERCASE
LOWER(column_or_string)  -- Converts to lowercase

Key points:

  • Takes a string argument (column name or literal string)
  • Returns a new string (doesn’t modify the original data in the database)
  • Works on any text data (VARCHAR, TEXT, CHAR)

Basic Examples

Convert Names to Uppercase

1
2
3
4
5
6
7
SELECT 
    first_name,
    UPPER(first_name) AS first_name_upper,
    last_name,
    UPPER(last_name) AS last_name_upper
FROM employees
LIMIT 5;

Expected output:

first_name first_name_upper last_name last_name_upper
Alice ALICE Johnson JOHNSON
Bob BOB Smith SMITH
Carol CAROL Williams WILLIAMS
David DAVID Brown BROWN
Eve EVE Davis DAVIS

The original data is unchanged — we’re just transforming the display.

Convert to Lowercase

1
2
3
4
5
SELECT 
    department_name,
    LOWER(department_name) AS department_lower
FROM departments
LIMIT 5;

Expected output:

department_name department_lower
Engineering engineering
Marketing marketing
Sales sales
Human Resources human resources
Finance finance

Going Deeper

Case-Insensitive Searching (One Use Case)

Find employees whose name starts with “a”, case-insensitive:

1
2
3
SELECT first_name, last_name
FROM employees
WHERE LOWER(first_name) LIKE 'a%';

Expected output:

first_name last_name
Alice Johnson

How it works: LOWER() converts “Alice” to “alice”, then LIKE 'a%' matches.

Note: In MySQL, LIKE is case-insensitive by default, so this example is actually redundant! But in some databases (PostgreSQL, for example), you’d need this technique.

Normalizing Input for Comparison

Compare user input (which might be any case) to database values:

1
2
3
4
-- Imagine a user types "engineering" (lowercase)
SELECT * 
FROM departments
WHERE LOWER(department_name) = LOWER('Engineering');

What this does: Converts both sides to lowercase, so “Engineering”, “engineering”, “ENGINEERING” all match.

Returns: The Engineering department.

Combining UPPER/LOWER with CONCAT

Format names as “LAST, First”:

1
2
3
4
5
SELECT 
    CONCAT(UPPER(last_name), ', ', first_name) AS formatted_name
FROM employees
ORDER BY last_name
LIMIT 5;

Expected output:

formatted_name
ANDERSON, Jack
BROWN, David
CLARK, Sam
DAVIS, Eve
GARCIA, Paul

Professional looking output with last names emphasized in caps.

Pause and Predict: What does UPPER(NULL) return?

Answer `NULL` All string functions return NULL if the input is NULL. This is the "NULL poison" effect we learned about in NULL handling.

Watch Out — Common Mistakes

Mistake #1: Thinking UPPER/LOWER Changes the Database

1
SELECT UPPER(first_name) FROM employees;

What beginners think: “This changes all first names to uppercase in the database.”

What actually happens: The query DISPLAYS names in uppercase, but the database is unchanged.

To actually change the database:

1
2
UPDATE employees
SET first_name = UPPER(first_name);

This permanently changes the data. Be very careful!

Mistake #2: Using UPPER/LOWER in WHERE Unnecessarily (Performance Issue)

1
2
3
--  SLOWER on large tables
SELECT * FROM employees
WHERE UPPER(first_name) = 'ALICE';

Why it’s slower: MySQL must convert every first_name to uppercase before comparing. On large tables, this prevents index usage.

Better:

1
2
3
-- • FASTER (MySQL LIKE is case-insensitive by default)
SELECT * FROM employees
WHERE first_name = 'Alice';

When UPPER/LOWER is needed: When you genuinely need case normalization, or when working with databases where comparisons are case-sensitive.

Mistake #3: Forgetting Mixed Case Exists

1
2
3
--  INCOMPLETE
SELECT * FROM employees
WHERE first_name = 'alice' OR first_name = 'ALICE';

What about: ‘Alice’, ‘ALice’, ‘AlIcE’, etc.?

Better:

1
2
3
-- • CORRECT
SELECT * FROM employees
WHERE LOWER(first_name) = 'alice';

This catches all case variations with one comparison.


Edge Case Spotlight

Non-ASCII Characters

UPPER() and LOWER() work with international characters:

1
2
3
4
SELECT 
    'café' AS original,
    UPPER('café') AS upper_case,
    LOWER('CAFÉ') AS lower_case;

Expected output:

original upper_case lower_case
café CAFÉ café

The é is handled correctly! MySQL’s character set (utf8mb4) supports international characters.

But be aware: Some special characters (like German ß) have unique uppercase rules. MySQL handles most cases correctly, but edge cases exist.


Try This

Exercise 1 (Guided)

Display all department names in lowercase, sorted alphabetically.

Hint SELECT LOWER(department_name), ORDER BY the result.

Exercise 2 (Independent)

Find all employees whose last name contains the letter “A” or “a” (case-insensitive). Show their full name.

Hint Use LOWER() or UPPER() with LIKE and the % wildcard.

Exercise 3 (Challenge)

Create a formatted email address for each employee: [email protected], all lowercase. Show first_name, last_name, and the generated email.

Hint Use LOWER() and CONCAT(). The format is: LOWER(first_name) + '.' + LOWER(last_name) + '@company.com'

Answer Key

Exercise 1 Answer ```sql SELECT LOWER(department_name) AS department_name_lower FROM departments ORDER BY department_name_lower; ``` **Or ORDER BY the original column:** ```sql SELECT LOWER(department_name) AS department_name_lower FROM departments ORDER BY department_name; ``` **Expected output:** | department_name_lower | |-----------------------| | business development | | customer support | | data science | | engineering | | finance | | human resources | | legal | | marketing | | ... | All in lowercase, alphabetical order.
Exercise 2 Answer ```sql SELECT first_name, last_name FROM employees WHERE LOWER(last_name) LIKE '%a%'; ``` **Or using UPPER:** ```sql SELECT first_name, last_name FROM employees WHERE UPPER(last_name) LIKE '%A%'; ``` **Expected output (partial):** | first_name | last_name | |------------|-----------| | Eve | Davis | | Paul | Garcia | | Noah | Harris | | Leo | Jackson | | Quinn | Martinez | | Olivia | Martin | | Grace | Taylor | All employees whose last name contains "a" or "A". **Note:** In MySQL, LIKE is case-insensitive by default, so `WHERE last_name LIKE '%a%'` works without LOWER/UPPER. But using LOWER/UPPER makes your intent explicit and works across all databases.
Exercise 3 Answer ```sql SELECT first_name, last_name, CONCAT(LOWER(first_name), '.', LOWER(last_name), '@company.com') AS email FROM employees; ``` **Expected output (partial):** | first_name | last_name | email | |------------|-----------|-------| | Alice | Johnson | [email protected] | | Bob | Smith | [email protected] | | Carol | Williams | [email protected] | | David | Brown | [email protected] | **Professional email addresses generated from names!**

Quick Recap

UPPER() converts text to uppercase
LOWER() converts text to lowercase
• These functions don’t change the database — only the display
• Useful for case-insensitive comparisons and data normalization
• Work with international characters (utf8mb4)
• Return NULL if input is NULL
• Be cautious about performance on large tables (indexed columns)


Part 1 Complete!

Congratulations! You’ve finished all 20 topics in Part 1 — Foundations. You can now:

  • Insert, update, delete data
  • Create, alter, drop tables
  • Query with SELECT, WHERE, ORDER BY, LIMIT
  • Use aggregate functions and GROUP BY
  • Understand primary and foreign keys
  • Join tables (INNER, LEFT, RIGHT)
  • Handle NULLs and duplicates
  • Manipulate strings

You have a solid SQL foundation!


Up Next

Next topic: SUBSTRINGpart2_01_substring.md

Ready for Part 2 — Intermediate techniques? Type ‘next’ to continue!

This post is licensed under CC BY 4.0 by the author.