Menu
Try in Playground

SQLite String Functions: SUBSTR, REPLACE, INSTR, and More

Practical string functions in SQLite — concatenation, SUBSTR, INSTR, REPLACE, TRIM, and the patterns for cleaning and reshaping text in queries.

This page includes runnable editors — edit, run, and see output instantly.

Strings Are Where Most Real Queries Live

Numbers are easy. Strings are where queries get messy — names with stray whitespace, emails in mixed case, IDs glued together with dashes, free-text fields that almost-but-not-quite match. SQLite ships a small, focused set of string functions that handle most of this without needing application code.

This page walks through the ones you'll reach for first: concatenation, slicing, searching, replacing, trimming, and formatting.

Concatenation Uses ||, Not CONCAT

SQLite doesn't have a CONCAT function. Strings are joined with the || operator:

Numbers and other types get coerced to text automatically. The catch: if any operand is NULL, the whole expression becomes NULL. That's standard SQL behavior, but it surprises people:

Wrap nullable columns in COALESCE(col, '') or COALESCE(col, 'default') when you want a missing value to not nuke the entire string.

Length, Upper, Lower

The three you'll use constantly:

LENGTH returns the number of characters for text, not bytes. If you actually want bytes (rare, but useful for storage analysis), use OCTET_LENGTH. UPPER and LOWER only transform ASCII letters by default — accented characters pass through unchanged unless you've loaded the ICU extension.

SUBSTR: Slicing Strings

SUBSTR(text, start, length) extracts a piece of a string. Indexes are 1-based — 1 is the first character, not 0:

A few things to remember:

  • The third argument is optional. Without it, you get everything from start to the end.
  • A negative start counts from the end of the string.
  • If start is past the end, you get an empty string, not an error.

SUBSTRING is accepted as a synonym, in case your muscle memory comes from another database.

INSTR: Finding a Substring

INSTR(haystack, needle) returns the 1-based position of the first occurrence of needle in haystack, or 0 if it's not found:

That last expression is the SQLite idiom for "everything before the @": find the delimiter with INSTR, then slice with SUBSTR. You'll write this combination often. Notice that INSTR returning 0 when nothing matches means you should check before slicing — feeding 0 into SUBSTR quietly gives weird results.

REPLACE: Swapping One Substring for Another

REPLACE(text, old, new) replaces every occurrence of old with new:

It's case-sensitive and doesn't take a regex — just a literal substring. For more complex transformations you can chain REPLACE calls, but past two or three nested ones it's time to do the work in the application instead.

TRIM, LTRIM, RTRIM

User-entered data tends to come with whitespace on the ends. TRIM strips it:

By default they remove spaces. Pass a second argument to specify which characters to strip — every character in the second argument is treated as a member of a "set to remove," not as a literal substring. So TRIM('xxxhelloxx', 'x') gives 'hello'.

printf: Formatting Numbers and Strings

When you need a formatted string — fixed decimal places, padded numbers, hex output — printf (also spelled format) does it:

The format specifiers follow C conventions, which means %d, %s, %f, %x, padding with 0 or spaces, and so on. This is much cleaner than building strings with || and a pile of CASTs.

LIKE vs GLOB: Pattern Matching

Two operators, two different worlds.

LIKE uses SQL's classic wildcards — % for any sequence of characters, _ for a single character — and is case-insensitive for ASCII:

GLOB uses Unix shell wildcards — * for any sequence, ? for a single character, [abc] for character classes — and is case-sensitive:

The picking-between-them rule: LIKE for human-style "starts with," "contains," "ends with" matching. GLOB when case sensitivity matters or you need character classes. Both can use indexes, but only when the pattern is anchored to the start ('foo%', not '%foo') — leading wildcards force a full scan.

Splitting Strings: There's No SPLIT

SQLite doesn't ship a SPLIT_STRING function. The two practical workarounds:

For splitting on a delimiter into multiple rows, the cleanest path is json_each over a JSON array, or a recursive CTE. We'll cover both in later chapters — for now, just know that "give me every word" isn't a one-liner in SQLite.

A Worked Example: Cleaning Up Names

Putting it together. Imagine a users table with messy display names — extra whitespace, mixed case, optional titles like "Dr. " or "Mr. " you want stripped:

The expression reads inside-out: strip outer whitespace, lowercase, drop the titles, trim again in case removing the title left a leading space. Each step is a single function — the complexity comes from stacking them. When the stack grows past three or four levels, that's a hint to either use a generated column (Chapter: Advanced Features) or do the cleaning during data import.

What You Take Away

  • || for concatenation; NULL poisons the result, so use COALESCE.
  • SUBSTR and INSTR together cover most "find and slice" needs.
  • REPLACE swaps every occurrence of a literal substring.
  • TRIM and friends accept a custom character set, not just whitespace.
  • printf is the right tool for formatted output.
  • LIKE for case-insensitive SQL wildcards, GLOB for case-sensitive shell-style patterns.

Next: Numeric Functions

Strings handled, the obvious next stop is numbers — rounding, absolute values, division quirks, and the math functions SQLite added in recent versions. That's the next page.

Frequently Asked Questions

How do you concatenate strings in SQLite?

Use the || operator, not CONCAT. SQLite doesn't have a CONCAT function by default — 'Hello, ' || name joins two strings into one. If any operand is NULL, the whole result is NULL, so wrap nullable columns in COALESCE when that's not what you want.

How do you get a substring in SQLite?

Use SUBSTR(text, start, length) — also spelled SUBSTRING. Indexes are 1-based: SUBSTR('hello', 1, 3) returns 'hel'. A negative start counts from the end, and the length argument is optional — leave it off to take everything to the end.

Does SQLite have a SPLIT_STRING function?

No — SQLite has no built-in split function. For most cases you can combine INSTR and SUBSTR to pull out the part you want, or use a recursive CTE to split on a delimiter. If you need it often, the json_each function on a JSON array is usually cleaner than rolling your own splitter.

What's the difference between LIKE and GLOB in SQLite?

LIKE is case-insensitive for ASCII by default and uses % and _ as wildcards. GLOB is case-sensitive and uses Unix shell wildcards (*, ?, [abc]). Reach for GLOB when you need case sensitivity or character classes; reach for LIKE for the more familiar SQL-style matching.

Coddy programming languages illustration

Learn to code with Coddy

GET STARTED