Complete reference for MariaDB string functions covering CONCAT, SUBSTRING, REPLACE, TRIM, REGEXP_REPLACE, LPAD, LOCATE, and 60+ more. Every function includes syntax, real SQL examples, and differences from MySQL and PostgreSQL string functions. Updated for MariaDB 11.x.
MariaDB string functions are built-in functions for text manipulation in MariaDB queries. MariaDB string functions are largely compatible with MySQL but include additional functions like REGEXP_REPLACE() (available natively since MariaDB 10.0.5, before MySQL added it) and NATURAL_SORT_KEY(). A key difference from PostgreSQL is that string concatenation uses CONCAT() rather than ||, and MariaDB string comparison is case-insensitive by default due to collation settings.
CONCAT
MariaDB 5.5+→ VARCHAR / TEXT
Concatenates one or more strings into a single string, returning NULL if any argument is NULL.
CONCAT returns NULL if ANY argument is NULL. Wrap nullable columns with COALESCE to get an empty string fallback. This is the most common source of silently missing data in report queries.
⚠Anti-Pattern— Using CONCAT when separator is constant
Writing CONCAT(col1, ', ', col2, ', ', col3) becomes unwieldy and breaks when any column is NULL.
✓ Instead: Use CONCAT_WS(', ', col1, col2, col3) — cleaner and NULL-safe for the value arguments.
CONCAT_WS skips NULL arguments automatically, so CONCAT_WS(', ', city, state, zip) never produces a leading or trailing comma when a column is NULL. Ideal for address formatting and dynamic tag lists.
example
SELECTCONCAT_WS(', ', city, state, country) FROMaddresses;
→-- 'London, England' (NULL state skipped)
◆MariaDB Note
Standard SQL function available in all MariaDB versions.
⇄ vs MySQL: Identical to MySQL.
⇄ vs PostgreSQL: PostgreSQL has CONCAT_WS with the same NULL-skipping semantics.
Returns the byte length of a string, which differs from character count for multi-byte character sets.
Signature
LENGTH(str)
Parameters
Parameter
Type
Description
str
VARCHAR
The string whose byte length is measured
Examples
ASCII string — bytes equal chars
sql
SELECTLENGTH('Hello');
→-- 5
UTF-8: 'é' is 2 bytes
sql
SELECTLENGTH('café');
→-- 5
On a column
sql
SELECTLENGTH(col) FROMproducts;
→-- byte length per row
Nested
sql
SELECTLENGTH(CONCAT('ab', 'cd'));
→-- 4
NULL input returns NULL
sql
SELECTLENGTH(NULL);
→-- NULL
⚠Anti-Pattern— Validating user-input length with LENGTH()
A 10-character Chinese string may return LENGTH() = 30 under utf8mb4, causing false 'too long' rejections.
✓ Instead: Use CHAR_LENGTH() for character-count validation.
LENGTH counts bytes, not characters. Under utf8mb4, a single emoji occupies 4 bytes — a 10-emoji username would return LENGTH() = 40 but CHAR_LENGTH() = 10. Always use CHAR_LENGTH for user-visible size limits.
Returns the number of characters in a string, regardless of multi-byte encoding.
Signatures
CHAR_LENGTH(str)
CHARACTER_LENGTH(str)
Parameters
Parameter
Type
Description
str
VARCHAR
The string to measure in characters
Examples
ASCII
sql
SELECTCHAR_LENGTH('Hello');
→-- 5
4 characters despite 5 bytes in UTF-8
sql
SELECTCHAR_LENGTH('café');
→-- 4
On a column
sql
SELECTCHAR_LENGTH(name) FROMcustomers;
→-- character count per row
Nested
sql
SELECTCHAR_LENGTH(REVERSE('abc'));
→-- 3
NULL handling
sql
SELECTCHAR_LENGTH(NULL);
→-- NULL
⚠Anti-Pattern— Mixing CHAR_LENGTH and LENGTH for the same check
Using both interchangeably in the same query creates confusing inconsistencies for multi-byte data.
✓ Instead: Pick CHAR_LENGTH for display/validation purposes and LENGTH only when you truly need byte sizes.
CHAR_LENGTH counts Unicode code points regardless of encoding, making it the right function for validating user-input length. It avoids the multi-byte trap of LENGTH() under utf8mb4.
example
SELECT*FROMusersWHERECHAR_LENGTH(username) >20;
→-- rows where display length exceeds 20
◆MariaDB Note
CHARACTER_LENGTH() is a synonym.
⇄ vs MySQL: Identical to MySQL.
⇄ vs PostgreSQL: PostgreSQL's CHAR_LENGTH() and CHARACTER_LENGTH() behave identically.
Synonym for CHAR_LENGTH(); returns the number of characters in a string.
Signature
CHARACTER_LENGTH(str)
Parameters
Parameter
Type
Description
str
VARCHAR
The string to measure
Examples
Basic usage
sql
SELECTCHARACTER_LENGTH('test');
→-- 4
3 CJK characters
sql
SELECTCHARACTER_LENGTH('日本語');
→-- 3
On a column
sql
SELECTCHARACTER_LENGTH(bio) FROMauthors;
→-- character count
Nested
sql
SELECTCHARACTER_LENGTH(TRIM(' hi '));
→-- 2
NULL handling
sql
SELECTCHARACTER_LENGTH(NULL);
→-- NULL
⚠Anti-Pattern— Confusing with LENGTH()
Using LENGTH() when you mean CHARACTER_LENGTH() gives wrong results for multi-byte character sets.
✓ Instead: Use CHARACTER_LENGTH() for character count, LENGTH() only for byte count.
CHARACTER_LENGTH is the SQL-standard name; CHAR_LENGTH is the shorthand. Both return identical results. Prefer CHARACTER_LENGTH when writing portable SQL that may run on PostgreSQL or other databases.
example
SELECTCHARACTER_LENGTH('Héllo');
→-- 5
◆MariaDB Note
Exact synonym for CHAR_LENGTH().
⇄ vs MySQL: Identical to MySQL.
⇄ vs PostgreSQL: Identical behavior in PostgreSQL.
Returns the byte (octet) length of a string; synonym for LENGTH() in MariaDB.
Signature
OCTET_LENGTH(str)
Parameters
Parameter
Type
Description
str
VARCHAR
The string whose byte count is returned
Examples
ASCII
sql
SELECTOCTET_LENGTH('abc');
→-- 3
3 chars × 3 bytes each in UTF-8
sql
SELECTOCTET_LENGTH('日本語');
→-- 9
On a column
sql
SELECTOCTET_LENGTH(content) FROMpages;
→-- byte size per row
Nested with HEX
sql
SELECTOCTET_LENGTH(HEX('a'));
→-- 2
NULL handling
sql
SELECTOCTET_LENGTH(NULL);
→-- NULL
⚠Anti-Pattern— Treating OCTET_LENGTH as character count
For multi-byte strings, OCTET_LENGTH can be several times CHAR_LENGTH, leading to wrong truncation logic.
✓ Instead: Use CHAR_LENGTH for character-count checks and OCTET_LENGTH only for raw storage/network-size calculations.
OCTET_LENGTH is a synonym for LENGTH in MariaDB, but using it makes your intent explicit: you're counting bytes for storage or protocol-size purposes, not character count. Useful when sizing VARCHAR columns for wire-protocol budgets.
Extracts a substring from a string, starting at a given position with an optional length.
Signatures
SUBSTRING(str, pos)
SUBSTRING(str, pos, len)
SUBSTRING(str FROM pos)
SUBSTRING(str FROM pos FOR len)
Parameters
Parameter
Type
Description
str
VARCHAR
Source string
pos
INT
1-based starting position; negative counts from the end
len
INT
Number of characters to extract (optional)
Examples
From position 7 to end
sql
SELECTSUBSTRING('Hello World', 7);
→-- 'World'
First 5 chars
sql
SELECTSUBSTRING('Hello World', 1, 5);
→-- 'Hello'
Negative pos counts from end
sql
SELECTSUBSTRING('Hello World', -5);
→-- 'World'
Nested
sql
SELECTSUBSTRING(UPPER('hello'), 2, 3);
→-- 'ELL'
NULL handling
sql
SELECTSUBSTRING(NULL, 1, 3);
→-- NULL
⚠Anti-Pattern— Off-by-one errors from 0-based thinking
MariaDB uses 1-based indexing. SUBSTRING(str, 0, 5) treats position 0 as position 1 and can return unexpected results.
✓ Instead: Always start positions at 1 for the first character.
SUBSTRING(str, -N) counts from the end of the string — no need to compute LEN-N first. This is the cleanest way to extract file extensions or domain suffixes.
example
SELECTSUBSTRING(filename, -3) FROMfiles;
→-- 'pdf', 'jpg', 'txt'
◆MariaDB Note
SUBSTR() and MID() are exact synonyms.
⇄ vs MySQL: Identical to MySQL.
⇄ vs PostgreSQL: PostgreSQL supports SUBSTRING(str FROM pos FOR len) SQL-standard syntax and also accepts regex patterns.
Synonym for SUBSTRING(); extracts part of a string by position and optional length.
Signatures
SUBSTR(str, pos)
SUBSTR(str, pos, len)
Parameters
Parameter
Type
Description
str
VARCHAR
Source string
pos
INT
1-based start position
len
INT
Length of substring (optional)
Examples
From position 5
sql
SELECTSUBSTR('database', 5);
→-- 'base'
First 4 chars
sql
SELECTSUBSTR('database', 1, 4);
→-- 'data'
On a column
sql
SELECTSUBSTR(tag, 2) FROMlabels;
→-- strips first char
Nested
sql
SELECTSUBSTR(CONCAT('ab','cd'), 2, 2);
→-- 'bc'
NULL length yields NULL
sql
SELECTSUBSTR('abc', 1, NULL);
→-- NULL
⚠Anti-Pattern— Assuming 0-based indexing
Coming from Python or JavaScript, developers often pass 0 as the start index, getting an empty or shifted result.
✓ Instead: Use 1 for the first character.
SUBSTR and SUBSTRING are 100% interchangeable in MariaDB. Choose one convention for your codebase; mixing them makes grep-based searches harder. SUBSTRING is more explicit and closer to the SQL standard.
Synonym for SUBSTRING(); extracts a substring starting at a position for a given length.
Signature
MID(str, pos, len)
Parameters
Parameter
Type
Description
str
VARCHAR
Source string
pos
INT
1-based starting position
len
INT
Number of characters to return
Examples
Classic MID usage
sql
SELECTMID('Hello World', 7, 5);
→-- 'World'
Middle slice
sql
SELECTMID('abcdef', 2, 3);
→-- 'bcd'
On a column
sql
SELECTMID(serial, 4, 6) FROMdevices;
→-- mid-section of serial
Nested
sql
SELECTMID(REPEAT('ab', 3), 2, 4);
→-- 'baba'
NULL len
sql
SELECTMID('test', 2, NULL);
→-- NULL
⚠Anti-Pattern— Relying on MID in cross-database SQL
MID is not standard SQL and absent in PostgreSQL and SQLite.
✓ Instead: Use SUBSTRING(str, pos, len) for maximum portability.
MID(str, pos, len) is an alias for SUBSTRING(str, pos, len). It exists for MySQL compatibility. New code should prefer SUBSTRING, which also works in PostgreSQL and other SQL dialects.
example
SELECTMID(order_ref, 5, 8) FROMorders;
→-- 8-char segment starting at position 5
◆MariaDB Note
Exact synonym for SUBSTRING().
⇄ vs MySQL: Identical to MySQL.
⇄ vs PostgreSQL: PostgreSQL does not have MID(); use SUBSTRING().
⚠Anti-Pattern— Over-truncating without checking length
LEFT('hi', 10) is safe (returns 'hi'), but dynamically computed lengths from user input can still produce unexpected empty strings if len = 0.
✓ Instead: Guard with GREATEST(len, 0) if length is computed.
LEFT(str, n) is the cleanest way to truncate a string to a maximum display width. For utf8mb4 columns it counts characters, not bytes, so it's safe for international text. Use it for preview snippets and slug generation.
example
SELECTLEFT(title, 50) ASpreviewFROMarticles;
→-- first 50 characters of title
◆MariaDB Note
Standard SQL function, available in all MariaDB versions.
⇄ vs MySQL: Identical to MySQL.
⇄ vs PostgreSQL: PostgreSQL has LEFT() with identical behavior.
⚠Anti-Pattern— Using RIGHT to check suffix instead of LIKE
WHERE RIGHT(col, 4) = '.pdf' is not index-friendly.
✓ Instead: Use WHERE col LIKE '%.pdf' which can leverage reverse-index tricks or full-text search.
RIGHT(str, n) is the mirror of LEFT. Combining it with LOCATE or CHAR_LENGTH lets you pull the extension from a filename without a regex: RIGHT(filename, CHAR_LENGTH(filename) - LOCATE('.', filename)).
Removes leading and/or trailing characters (default: spaces) from a string.
Signatures
TRIM(str)
TRIM(LEADING remstr FROM str)
TRIM(TRAILING remstr FROM str)
TRIM(BOTH remstr FROM str)
Parameters
Parameter
Type
Description
str
VARCHAR
The string to trim
remstr
VARCHAR
Character(s) to remove (default is space)
Examples
Removes surrounding spaces
sql
SELECTTRIM(' Hello ');
→-- 'Hello'
Remove leading zeros
sql
SELECTTRIM(LEADING'0'FROM'00123');
→-- '123'
Remove trailing dots
sql
SELECTTRIM(TRAILING'.'FROM'end...');
→-- 'end'
Trim both sides
sql
SELECTTRIM(BOTH'x'FROM'xxhelloxx');
→-- 'hello'
NULL handling
sql
SELECTTRIM(NULL);
→-- NULL
⚠Anti-Pattern— Expecting TRIM to strip interior spaces
TRIM only removes characters from the edges of the string, not internal whitespace.
✓ Instead: Use REGEXP_REPLACE(str, '\\s+', ' ') to collapse internal whitespace.
TRIM can strip any character, not just spaces: TRIM(LEADING '/' FROM path) removes leading slashes. This is cleaner than chaining LTRIM/RTRIM when you need to strip a specific delimiter.
example
SELECTTRIM(BOTH'"'FROMraw_value) FROMimports;
→-- 'hello' (quotes stripped from '"hello"')
◆MariaDB Note
Standard SQL function, available in all MariaDB versions.
⇄ vs MySQL: Identical to MySQL.
⇄ vs PostgreSQL: PostgreSQL TRIM() supports identical LEADING/TRAILING/BOTH syntax.
⚠Anti-Pattern— Using LTRIM to strip non-space whitespace
LTRIM does not remove \t, \n, or \r characters.
✓ Instead: Use REGEXP_REPLACE(str, '^[[:space:]]+', '') to strip all leading whitespace.
User-input data often has leading spaces that cause WHERE col = 'value' to miss matches. Apply LTRIM in an UPDATE to clean up imported data rather than repeating the workaround in every query.
Removes trailing (right-side) spaces from a string.
Signature
RTRIM(str)
Parameters
Parameter
Type
Description
str
VARCHAR
String to right-trim
Examples
Strips trailing spaces
sql
SELECTRTRIM('Hello ');
→-- 'Hello'
Leading spaces kept
sql
SELECTRTRIM(' Hello ');
→-- ' Hello'
On a column
sql
SELECTRTRIM(description) FROMproducts;
→-- trailing-trimmed
Combining for full trim
sql
SELECTRTRIM(LTRIM(' hi '));
→-- 'hi'
NULL handling
sql
SELECTRTRIM(NULL);
→-- NULL
⚠Anti-Pattern— Forgetting that VARCHAR does not pad but CHAR does
CHAR(10) columns store trailing spaces; RTRIM is needed for equality checks on CHAR columns.
✓ Instead: Compare CHAR columns with RTRIM(col) = 'value' or switch to VARCHAR.
CHAR columns are space-padded to their declared length; RTRIM removes this padding when you need to compare or display the raw value. VARCHAR does not need this, but legacy CHAR migrations often do.
Left-pads a string with a given pad string until it reaches the specified total length.
Signature
LPAD(str, len, padstr)
Parameters
Parameter
Type
Description
str
VARCHAR
String to pad
len
INT
Desired total length of the result
padstr
VARCHAR
String used for padding
Examples
Zero-pad a number
sql
SELECTLPAD('42', 6, '0');
→-- '000042'
Dash padding
sql
SELECTLPAD('hi', 5, '-');
→-- '---hi'
On a column
sql
SELECTLPAD(invoice_num, 8, '0') FROMorders;
→-- zero-padded IDs
Nested
sql
SELECTLPAD(LTRIM(' abc'), 6, '*');
→-- '***abc'
Truncates when str longer than len
sql
SELECTLPAD('toolong', 3, 'x');
→-- 'too'
⚠Anti-Pattern— Padding NULLs without checking
LPAD(NULL, 5, '0') returns NULL, which may break report formatting.
✓ Instead: Use LPAD(COALESCE(col, ''), 5, '0') to treat NULL as an empty string.
LPAD is the standard way to left-pad invoice numbers, order IDs, or version strings so that alphabetic sort equals numeric sort. Always specify the full target length to avoid silent truncation.
Right-pads a string with a given pad string until it reaches the specified total length.
Signature
RPAD(str, len, padstr)
Parameters
Parameter
Type
Description
str
VARCHAR
String to pad
len
INT
Desired total length
padstr
VARCHAR
String used for padding on the right
Examples
Dot padding
sql
SELECTRPAD('hello', 8, '.');
→-- 'hello...'
Right zero-pad
sql
SELECTRPAD('42', 6, '0');
→-- '420000'
On a column
sql
SELECTRPAD(code, 10, '-') FROMitems;
→-- fixed-width codes
Nested
sql
SELECTRPAD(UPPER('hi'), 6, '!');
→-- 'HI!!!!'
Truncates if already longer
sql
SELECTRPAD('toolong', 3, 'x');
→-- 'too'
⚠Anti-Pattern— Using a multi-char padstr and assuming it tiles exactly
RPAD('x', 5, 'ab') yields 'xabab' — the pad string is cut if it doesn't divide evenly.
✓ Instead: That is expected behavior; just be aware the pad string repeats and gets truncated at the target length.
RPAD is useful for generating fixed-width export files where columns must occupy an exact number of characters. Combine with SUBSTR to cap length and then pad in one pass.
Converts a string to uppercase using the current character set collation rules.
Signature
UPPER(str)
Parameters
Parameter
Type
Description
str
VARCHAR
String to convert to uppercase
Examples
Basic uppercase
sql
SELECTUPPER('hello');
→-- 'HELLO'
Mixed input
sql
SELECTUPPER('MariaDB 10.6');
→-- 'MARIADB 10.6'
On a column
sql
SELECTUPPER(username) FROMusers;
→-- uppercased usernames
Nested
sql
SELECTUPPER(CONCAT('foo', 'bar'));
→-- 'FOOBAR'
NULL handling
sql
SELECTUPPER(NULL);
→-- NULL
⚠Anti-Pattern— Using UPPER() in WHERE to force case-insensitive match
WHERE UPPER(col) = UPPER('value') disables index use on col.
✓ Instead: Set the column collation to a _ci variant and query directly: WHERE col = 'value'.
Running UPPER in every SELECT query adds CPU overhead on large tables. Better to store case-normalized values (or use a case-insensitive collation) and apply UPPER only during INSERT/UPDATE.
Converts a string to lowercase using the current character set collation rules.
Signature
LOWER(str)
Parameters
Parameter
Type
Description
str
VARCHAR
String to convert to lowercase
Examples
Basic lowercase
sql
SELECTLOWER('HELLO');
→-- 'hello'
Mixed case
sql
SELECTLOWER('MariaDB');
→-- 'mariadb'
On a column
sql
SELECTLOWER(email) FROMaccounts;
→-- lowercased emails
Nested
sql
SELECTLOWER(CONCAT('FOO', 'BAR'));
→-- 'foobar'
NULL handling
sql
SELECTLOWER(NULL);
→-- NULL
⚠Anti-Pattern— Normalizing case at query time instead of storage time
WHERE LOWER(email) = 'user@example.com' prevents index use.
✓ Instead: Store email as LOWER(email) via a BEFORE INSERT trigger or application logic, then query directly.
Email addresses should be stored in lowercase to prevent 'User@Example.com' and 'user@example.com' appearing as different accounts. Apply LOWER during INSERT and in a one-time data-cleanse UPDATE.
example
INSERTINTOusers (email) VALUES (LOWER(TRIM(?)));
→-- 'User@Example.com' stored as 'user@example.com'
◆MariaDB Note
LCASE() is a synonym.
⇄ vs MySQL: Identical to MySQL.
⇄ vs PostgreSQL: PostgreSQL LOWER() behaves identically.
Synonym for UPPER(); converts a string to uppercase.
Signature
UCASE(str)
Parameters
Parameter
Type
Description
str
VARCHAR
String to uppercase
Examples
Basic
sql
SELECTUCASE('hello');
→-- 'HELLO'
Unicode
sql
SELECTUCASE('café');
→-- 'CAFÉ'
On a column
sql
SELECTUCASE(name) FROMbrands;
→-- uppercased brand names
Nested
sql
SELECTUCASE(TRIM(' hi '));
→-- 'HI'
NULL handling
sql
SELECTUCASE(NULL);
→-- NULL
⚠Anti-Pattern— Mixing UCASE and UPPER in the same codebase
Having both aliases in queries is confusing for maintainers.
✓ Instead: Standardize on UPPER() across all queries.
UCASE and UPPER are identical in MariaDB. Using UPPER is preferred because it matches the SQL standard and works in PostgreSQL, DB2, and other databases without modification.
example
SELECTUCASE(country) FROMaddresses;
→-- 'UNITED KINGDOM'
◆MariaDB Note
Exact synonym for UPPER().
⇄ vs MySQL: Identical to MySQL.
⇄ vs PostgreSQL: PostgreSQL does not have UCASE(); use UPPER().
⚠Anti-Pattern— Using REPLACE for pattern-based substitution
REPLACE only does literal string matching — it cannot handle wildcards or patterns.
✓ Instead: Use REGEXP_REPLACE for pattern-based replacement.
REPLACE inside an UPDATE is the most efficient way to do bulk find-and-replace in a column — no need to fetch rows to the application layer. It's case-sensitive by default; for case-insensitive replacement, combine with LOWER or a collation change.
Returns the string with characters in reverse order.
Signature
REVERSE(str)
Parameters
Parameter
Type
Description
str
VARCHAR
String to reverse
Examples
Basic reversal
sql
SELECTREVERSE('Hello');
→-- 'olleH'
Alphabet slice
sql
SELECTREVERSE('abcde');
→-- 'edcba'
On a column
sql
SELECTREVERSE(serial) FROMparts;
→-- reversed serials
Nested
sql
SELECTREVERSE(UPPER('hello'));
→-- 'OLLEH'
NULL handling
sql
SELECTREVERSE(NULL);
→-- NULL
⚠Anti-Pattern— Using REVERSE in WHERE for suffix matching
WHERE REVERSE(col) LIKE 'moc.%' disables index use on col.
✓ Instead: Store a reversed_col computed column with an index and query that column directly.
B-tree indexes support prefix queries (LIKE 'abc%') but not suffix queries (LIKE '%xyz'). Store a REVERSE() copy of the column and query LIKE 'zyx%' on it for efficient suffix searching.
Returns a string repeated N times; returns an empty string if count is less than 1.
Signature
REPEAT(str, count)
Parameters
Parameter
Type
Description
str
VARCHAR
String to repeat
count
INT
Number of repetitions
Examples
Three repetitions
sql
SELECTREPEAT('ab', 3);
→-- 'ababab'
Horizontal rule
sql
SELECTREPEAT('-', 20);
→-- '--------------------'
On a column
sql
SELECTREPEAT('*', rating) FROMreviews;
→-- star rating display
Nested
sql
SELECTREPEAT(UPPER('ha'), 3);
→-- 'HAHAHA'
Zero count returns empty string
sql
SELECTREPEAT('x', 0);
→-- ''
⚠Anti-Pattern— Repeating with a large count from user input
REPEAT('x', 1000000) can produce a very large string and exhaust memory.
✓ Instead: Cap count with LEAST(user_count, 255) before passing to REPEAT.
REPEAT is handy for generating separator strings, building fixed-width output, or creating test data. Avoid very large repeat counts in production queries as the result is fully materialized in memory.
⚠Anti-Pattern— Using SPACE for alignment instead of LPAD/RPAD
Manual CONCAT with SPACE for padding is verbose and error-prone.
✓ Instead: Use LPAD or RPAD for fixed-width alignment.
SPACE(n) is cleaner than REPEAT(' ', n) when you need to insert whitespace for formatting. It clearly communicates intent and is slightly more readable in complex CONCAT expressions.
LOCATE(substr, str, pos) starts searching at position pos, which lets you find the second or Nth occurrence by chaining calls: LOCATE(sub, str, LOCATE(sub, str) + 1).
Returns the position of the first occurrence of a substring in a string; returns 0 if not found.
Signature
INSTR(str, substr)
Parameters
Parameter
Type
Description
str
VARCHAR
String to search within
substr
VARCHAR
Substring to search for
Examples
Finds 'World' at position 7
sql
SELECTINSTR('Hello World', 'World');
→-- 7
First occurrence only
sql
SELECTINSTR('abcabc', 'bc');
→-- 2
On a column
sql
SELECTINSTR(path, '/') FROMfiles;
→-- position of first slash
Find last occurrence via REVERSE
sql
SELECTINSTR(REVERSE('hello'), 'l');
→-- 1
NULL handling
sql
SELECTINSTR('abc', NULL);
→-- NULL
⚠Anti-Pattern— Confusing INSTR and LOCATE argument order
INSTR(str, substr) and LOCATE(substr, str) have reversed argument orders — a common source of bugs.
✓ Instead: Pick one function and use it consistently. LOCATE is closer to the SQL standard POSITION syntax.
INSTR(str, substr) is the two-argument form that mirrors Oracle's convention, making migrations easier. Use LOCATE when you need a start position; use INSTR for simple 'does this substring exist' checks.
example
SELECT*FROMproductsWHEREINSTR(tags, 'sale') >0;
→-- rows where tags contain 'sale'
◆MariaDB Note
Standard SQL function, available in all MariaDB versions.
⇄ vs MySQL: Identical to MySQL.
⇄ vs PostgreSQL: PostgreSQL uses STRPOS(str, substr) for the same purpose.
SQL-standard syntax equivalent to LOCATE(substr, str); returns the position of a substring within a string.
Signature
POSITION(substr IN str)
Parameters
Parameter
Type
Description
substr
VARCHAR
Substring to locate
str
VARCHAR
String to search within
Examples
Standard syntax
sql
SELECTPOSITION('bar'IN'foobar');
→-- 4
Not found returns 0
sql
SELECTPOSITION('x'IN'hello');
→-- 0
On a column
sql
SELECTPOSITION('@'INemail) FROMusers;
→-- @ position
Nested
sql
SELECTPOSITION('o'INLOWER('FOO'));
→-- 1
NULL handling
sql
SELECTPOSITION(NULLIN'test');
→-- NULL
⚠Anti-Pattern— Forgetting IN keyword
Writing POSITION('x', 'str') (comma syntax) is a syntax error — the IN keyword is mandatory.
✓ Instead: Use POSITION('x' IN 'str') or switch to LOCATE('x', 'str').
POSITION(substr IN str) is the SQL-standard form and is also valid in PostgreSQL. Prefer it in cross-database SQL scripts over LOCATE() to maximize portability.
example
SELECTPOSITION('@'INemail) ASat_posFROMusers;
→-- position of '@' in each email
◆MariaDB Note
Standard SQL function, available in all MariaDB versions.
⇄ vs MySQL: Identical to MySQL.
⇄ vs PostgreSQL: PostgreSQL POSITION(substr IN str) behaves identically.
Returns the 1-based position of a string in a comma-separated list, or 0 if not found.
Signature
FIND_IN_SET(str, strlist)
Parameters
Parameter
Type
Description
str
VARCHAR
String to search for
strlist
VARCHAR
Comma-separated list of values
Examples
Position in list
sql
SELECTFIND_IN_SET('b', 'a,b,c,d');
→-- 2
Not found returns 0
sql
SELECTFIND_IN_SET('e', 'a,b,c,d');
→-- 0
Filter rows
sql
SELECT*FROMtWHEREFIND_IN_SET('admin', roles) >0;
→-- rows with 'admin' role
Case-insensitive via LOWER
sql
SELECTFIND_IN_SET(LOWER('B'), LOWER('a,B,c'));
→-- 2
NULL handling
sql
SELECTFIND_IN_SET(NULL, 'a,b,c');
→-- NULL
⚠Anti-Pattern— Storing multi-value data as comma-separated strings
Querying comma-separated columns with FIND_IN_SET cannot use indexes and makes JOINs impossible.
✓ Instead: Use a proper junction/bridge table or MariaDB's native SET column type.
FIND_IN_SET('admin', roles) is safer than LIKE '%admin%' which would also match 'superadmin'. It returns the 1-based position or 0 if not found, and correctly handles list boundaries.
Compares two strings and returns 0 if equal, -1 if the first is less than the second, or 1 if greater.
Signature
STRCMP(str1, str2)
Parameters
Parameter
Type
Description
str1
VARCHAR
First string to compare
str2
VARCHAR
Second string to compare
Examples
Equal strings
sql
SELECTSTRCMP('abc', 'abc');
→-- 0
'abc' < 'abd'
sql
SELECTSTRCMP('abc', 'abd');
→-- -1
'abd' > 'abc'
sql
SELECTSTRCMP('abd', 'abc');
→-- 1
Nested case normalization
sql
SELECTSTRCMP(LOWER(a), LOWER(b)) FROMt;
→-- case-insensitive compare
NULL handling
sql
SELECTSTRCMP('a', NULL);
→-- NULL
⚠Anti-Pattern— Using STRCMP for equality instead of =
WHERE STRCMP(col, 'value') = 0 is more verbose and slightly slower than WHERE col = 'value'.
✓ Instead: Use = for equality; use STRCMP only when you need the three-way comparison (-1/0/1) for ordering logic.
STRCMP returns -1, 0, or 1, giving you a clear ordering signal suitable for CASE expressions. It respects the column collation, so case sensitivity follows your table definition.
⚠Anti-Pattern— Parsing CSV with SUBSTRING_INDEX in production
Nesting SUBSTRING_INDEX calls for every column in a CSV string is fragile and non-indexable.
✓ Instead: Use JSON_TABLE or normalize the data into separate columns.
SUBSTRING_INDEX is the most readable way to extract segments from delimited strings. Use positive count for prefix, negative for suffix. Chain two calls to extract a middle segment.
⚠Anti-Pattern— Confusing INSERT string function with INSERT statement
INSERT(str,...) is a string function, not a DML statement — beginners sometimes confuse the two.
✓ Instead: Remember: string INSERT takes 4 arguments; the SQL INSERT statement is a different keyword.
INSERT(str, pos, len, newstr) replaces len characters starting at pos. It's more readable than CONCAT(LEFT(...), newstr, SUBSTRING(...)) when you know the position. Used in data masking to redact credit card middle digits.
⚠Anti-Pattern— Using ELT as a substitute for a lookup table
Hardcoding a long list of values in ELT() is brittle and hard to maintain.
✓ Instead: Store lookup data in a reference table and JOIN to it.
ELT(N, 'a','b','c') returns the Nth string — effectively a small inline array. Useful for converting numeric status codes to labels without a JOIN, but only practical for lists up to ~10 items.
⚠Anti-Pattern— Using FIELD for a large number of values
FIELD with 20+ values becomes unreadable and is re-evaluated for every row.
✓ Instead: Use a lookup table with an explicit rank column and JOIN for large ordered sets.
FIELD(value, list...) returns the 1-based position of value in the list, or 0 if not found. Use it in ORDER BY to sort rows in a specific custom order rather than alphabetically or by ID.
Formats a number with a fixed number of decimal places and thousands separators, returning a string.
Signatures
FORMAT(num, decimal_places)
FORMAT(num, decimal_places, locale)
Parameters
Parameter
Type
Description
num
NUMERIC
Number to format
decimal_places
INT
Number of decimal places to display
locale
VARCHAR
Locale string for separators, e.g. 'de_DE' (optional)
Examples
Thousands separator + 2 decimals
sql
SELECTFORMAT(1234567.891, 2);
→-- '1,234,567.89'
No decimal places
sql
SELECTFORMAT(9999, 0);
→-- '9,999'
On a column
sql
SELECTFORMAT(price, 2) FROMproducts;
→-- formatted prices
German locale
sql
SELECTFORMAT(1234.5, 2, 'de_DE');
→-- '1.234,50'
NULL handling
sql
SELECTFORMAT(NULL, 2);
→-- NULL
⚠Anti-Pattern— Using FORMAT in calculations
SELECT FORMAT(price, 2) * qty will silently cast back to float and lose the formatting intent, or error on locale separators.
✓ Instead: Format numbers only in the SELECT list for display, never in WHERE or JOIN conditions.
FORMAT(1234567.891, 2) returns '1,234,567.89' as a string — perfect for reports but unsuitable for further arithmetic. Never store FORMAT output back into a numeric column.
Returns the hexadecimal string representation of a string or integer argument.
Signatures
HEX(str)
HEX(n)
Parameters
Parameter
Type
Description
str / n
VARCHAR / INT
String to encode or integer to convert to hex
Examples
Hex encoding of string
sql
SELECTHEX('abc');
→-- '616263'
Integer to hex
sql
SELECTHEX(255);
→-- 'FF'
On a column
sql
SELECTHEX(data) FROMblobs;
→-- hex-encoded BLOB
Nested round-trip
sql
SELECTHEX(UNHEX('41'));
→-- '41'
NULL handling
sql
SELECTHEX(NULL);
→-- NULL
⚠Anti-Pattern— Storing hex-encoded data and forgetting to decode it
Querying hex-encoded columns for substring matches fails because the pattern must also be hex-encoded.
✓ Instead: Use UNHEX before comparison or switch to proper BLOB/VARBINARY types.
HEX() converts binary blobs or integers to a safe uppercase hex string. It's the lightest encoding option (2 bytes per input byte) compared to TO_BASE64 (4/3 ratio). Use for checksums, binary ID display, and debugging.
example
SELECTHEX(uuid_col) FROMsessions;
→-- '550E8400E29B41D4A716446655440000'
◆MariaDB Note
Standard SQL function, available in all MariaDB versions.
⇄ vs MySQL: Identical to MySQL.
⇄ vs PostgreSQL: PostgreSQL uses ENCODE(data, 'hex') or the \x literal prefix.
Converts a hexadecimal string back to the binary string it represents.
Signature
UNHEX(str)
Parameters
Parameter
Type
Description
str
VARCHAR
Hexadecimal string to decode
Examples
Hex to string
sql
SELECTUNHEX('616263');
→-- 'abc'
Single byte
sql
SELECTUNHEX('FF');
→-- 0xFF byte
On a column
sql
SELECTUNHEX(hex_col) FROMencoded_data;
→-- decoded values
Round-trip
sql
SELECTHEX(UNHEX('4D617269614442'));
→-- '4D617269614442'
Invalid hex returns NULL
sql
SELECTUNHEX('ZZ');
→-- NULL
⚠Anti-Pattern— Passing odd-length hex strings
UNHEX('ABC') has an odd number of hex digits and returns NULL.
✓ Instead: Ensure the hex string is even-length: LPAD(hex_str, CHAR_LENGTH(hex_str) + MOD(CHAR_LENGTH(hex_str),2), '0').
UNHEX is the inverse of HEX. Use it when inserting binary UUIDs or hashes provided as hex strings. Storing UUIDs as BINARY(16) via UNHEX uses 16 bytes vs 36 bytes for the text form.
Returns the ASCII (numeric) value of the leftmost character of a string.
Signature
ASCII(str)
Parameters
Parameter
Type
Description
str
VARCHAR
String whose first character's ASCII code is returned
Examples
Uppercase A
sql
SELECTASCII('A');
→-- 65
Lowercase a
sql
SELECTASCII('a');
→-- 97
Only first character used
sql
SELECTASCII('Hello');
→-- 72
Round-trip with CHAR
sql
SELECTASCII(CHAR(65));
→-- 65
NULL handling
sql
SELECTASCII(NULL);
→-- NULL
⚠Anti-Pattern— Using ASCII for multi-byte Unicode characters
ASCII('é') returns 195 (the first UTF-8 byte), not the Unicode code point 233.
✓ Instead: Use ORD() which returns the full Unicode code point for multi-byte characters.
ASCII returns the numeric code of the first character. Values < 32 indicate control characters; values > 127 indicate non-ASCII. Use in a WHERE clause to audit imported data for hidden characters.
Returns the character(s) corresponding to the given integer code point(s); multi-byte characters supported with USING charset.
Signatures
CHAR(n, ...)
CHAR(n, ... USING charset_name)
Parameters
Parameter
Type
Description
n, ...
INT
One or more integer code point values
charset_name
VARCHAR
Character set to interpret the code points (optional)
Examples
ASCII code 65
sql
SELECTCHAR(65);
→-- 'A'
Multiple chars
sql
SELECTCHAR(72, 101, 108, 108, 111);
→-- 'Hello'
Tab character
sql
SELECTCHAR(9);
→-- '\t'
UTF-8 multi-byte
sql
SELECTCHAR(0xC3, 0xA9USINGutf8mb4);
→-- 'é'
NULL args are skipped
sql
SELECTCHAR(NULL);
→-- ''
⚠Anti-Pattern— Using CHAR without USING for non-ASCII code points
CHAR(233) without a charset clause may return the wrong byte sequence depending on the connection charset.
✓ Instead: Always specify USING utf8mb4 when generating non-ASCII characters.
CHAR(9) is a tab, CHAR(10) is a newline, CHAR(13) is a carriage return. Using CHAR() instead of literal escape characters makes queries more readable and avoids editor/encoding issues.
Returns the code point of the leftmost character of a string, handling multi-byte characters correctly.
Signature
ORD(str)
Parameters
Parameter
Type
Description
str
VARCHAR
String whose first character's code point is returned
Examples
ASCII character
sql
SELECTORD('A');
→-- 65
Unicode code point for é
sql
SELECTORD('é');
→-- 233
On a column
sql
SELECTORD(col) FROMt;
→-- code point per row
Round-trip star symbol
sql
SELECTORD(CHAR(9733));
→-- 9733
NULL handling
sql
SELECTORD(NULL);
→-- NULL
⚠Anti-Pattern— Using ASCII() on utf8mb4 columns
ASCII('é') returns 195 (first UTF-8 byte), not the human-readable code point 233.
✓ Instead: Use ORD() when the column may contain multi-byte characters.
ASCII only returns the value of the first byte; ORD returns the full multi-byte code point. For utf8mb4 data, ORD gives the correct Unicode code point while ASCII would return an incorrect partial value.
example
SELECTORD('é');
→-- 50089 (correct UTF-8 code point, not 195)
◆MariaDB Note
Standard SQL function, available in all MariaDB versions.
⇄ vs MySQL: Identical to MySQL.
⇄ vs PostgreSQL: PostgreSQL uses ASCII(str) which correctly returns Unicode code points.
Returns the length of a string in bits (8 × byte length).
Signature
BIT_LENGTH(str)
Parameters
Parameter
Type
Description
str
VARCHAR
String to measure in bits
Examples
3 bytes × 8 bits
sql
SELECTBIT_LENGTH('abc');
→-- 24
3 bytes in UTF-8 × 8
sql
SELECTBIT_LENGTH('日');
→-- 24
On a column
sql
SELECTBIT_LENGTH(data) FROMmessages;
→-- bit sizes
Single byte
sql
SELECTBIT_LENGTH(CHAR(255));
→-- 8
NULL handling
sql
SELECTBIT_LENGTH(NULL);
→-- NULL
⚠Anti-Pattern— Confusing BIT_LENGTH with character count
BIT_LENGTH returns bits, not characters — 'Hello' is 40 bits, not 5.
✓ Instead: Use CHAR_LENGTH() for character count, LENGTH() for byte count, BIT_LENGTH() only for bit-level calculations.
BIT_LENGTH returns the number of bits (8 × bytes). It's rarely needed for string data but is the right function when working with binary protocols or measuring bitfield storage. Under utf8mb4, each character may be 8-32 bits.
⚠Anti-Pattern— Using SOUNDEX for non-English names
Soundex is designed for English phonetics and gives poor results for names in other languages.
✓ Instead: For multilingual fuzzy matching, use the fuzzymatch extension or a dedicated search engine.
SOUNDEX encodes a string to its phonetic representation, so 'Smith' and 'Smyth' share the same code. Pre-compute and store the SOUNDEX of name columns to run fast phonetic lookups without full-table scans.
Returns a string quoted and escaped so it can be used safely as a SQL string literal.
Signature
QUOTE(str)
Parameters
Parameter
Type
Description
str
VARCHAR
String to quote and escape
Examples
Basic quoting
sql
SELECTQUOTE('hello');
→-- "'hello'"
Single quote escaped
sql
SELECTQUOTE('it\'satest');
→-- "'it\'s a test'"
On a column
sql
SELECTQUOTE(user_input) FROMlogs;
→-- safely quoted values
Nested
sql
SELECTQUOTE(CONCAT('foo', 'bar'));
→-- "'foobar'"
NULL returns the string 'NULL'
sql
SELECTQUOTE(NULL);
→-- 'NULL'
⚠Anti-Pattern— Relying on QUOTE() to prevent SQL injection from application code
QUOTE() is designed for use inside SQL (e.g., stored procedures), not as an application-layer sanitizer.
✓ Instead: Use parameterized queries / prepared statements in your application code.
QUOTE wraps a string in single quotes and escapes interior quotes and special characters, producing a value safe for embedding in a SQL statement. This is useful in stored procedures that build audit log entries.
example
SELECTCONCAT('INSERT INTO audit VALUES (', QUOTE(user_action), ')') FROMevents;
→-- 'INSERT INTO audit VALUES (\'login\')'
◆MariaDB Note
QUOTE(NULL) returns the unquoted string 'NULL', unlike most functions that return NULL.
⇄ vs MySQL: Identical to MySQL.
⇄ vs PostgreSQL: PostgreSQL uses QUOTE_LITERAL() and QUOTE_NULLABLE() for the same purpose.
Returns the character set name of a string argument.
Signature
CHARSET(str)
Parameters
Parameter
Type
Description
str
VARCHAR
String whose character set is inspected
Examples
Default connection charset
sql
SELECTCHARSET('hello');
→-- 'utf8mb4'
After conversion
sql
SELECTCHARSET(CONVERT('hello'USINGlatin1));
→-- 'latin1'
On a column
sql
SELECTCHARSET(name) FROMcustomers;
→-- charset of column data
Nested
sql
SELECTCHARSET(LOWER('ABC'));
→-- 'utf8mb4'
NULL returns 'binary'
sql
SELECTCHARSET(NULL);
→-- 'binary'
⚠Anti-Pattern— Assuming all string columns share the same charset
Joining a utf8mb4 column with a latin1 column causes implicit conversion and can break index use.
✓ Instead: Check CHARSET(col) and align column charsets at table-design time.
CHARSET() reveals which character set a string expression uses. Collation mismatches between two columns — e.g., utf8mb4 vs latin1 — prevent index use and can cause 'Illegal mix of collations' errors. Use CHARSET() to spot the problem.
example
SELECTCHARSET(col1), CHARSET(col2) FROMt1LIMIT1;
→-- 'utf8mb4', 'latin1' — mismatch identified
◆MariaDB Note
MariaDB/MySQL-specific metadata function, not available in other databases.
⇄ vs MySQL: Identical to MySQL.
⇄ vs PostgreSQL: PostgreSQL has no CHARSET(); the database has a single encoding checked with pg_encoding_to_char(encoding).
COERCIBILITY returns a value 0-6 indicating how easily the collation of a string can be converted. Lower values override higher ones in comparisons. When two operands have the same coercibility but different collations, MariaDB raises an error — use this function to identify which side needs an explicit COLLATE clause.
⚠Anti-Pattern— Assuming default collation is case-sensitive
Many MariaDB defaults use _ci (case-insensitive) collations, so 'ABC' = 'abc' is TRUE.
✓ Instead: Check COLLATION(col) and use _bin or _cs collations when case-sensitivity matters.
COLLATION() returns the collation name of a string expression. Use it to confirm that a CONVERT or COLLATE clause took effect, especially after changing a table's character set without recreating indexes.
⚠Anti-Pattern— Using REGEXP_REPLACE when REPLACE() suffices
REGEXP_REPLACE is slower than REPLACE for simple literal substitutions.
✓ Instead: Use REPLACE() for literal find-and-replace; reserve REGEXP_REPLACE for pattern-based work.
REGEXP_REPLACE lets you do pattern-based substitutions that REPLACE() cannot handle. It's particularly useful for stripping HTML tags, normalizing phone numbers, or collapsing multiple spaces. Available from MariaDB 10.0.5 via PCRE.
⚠Anti-Pattern— Using REGEXP_SUBSTR to extract a known-position field
If the position is fixed (e.g. the 2nd CSV field), REGEXP_SUBSTR is overkill.
✓ Instead: Use SUBSTRING_INDEX for delimiter-based extraction when the pattern is simple.
REGEXP_SUBSTR returns the first substring matching a PCRE pattern. Useful for extracting structured tokens like postal codes, phone numbers, or version strings from unstructured text columns.
0=start of match, 1=position after match (optional)
match_type
VARCHAR
Flags (optional)
Examples
Position of first 'o'
sql
SELECTREGEXP_INSTR('Hello World', 'o');
→-- 5
First digit position
sql
SELECTREGEXP_INSTR('abc123', '[0-9]');
→-- 4
On a column
sql
SELECTREGEXP_INSTR(text, '[A-Z]') FROMdocs;
→-- first uppercase pos
Position after match
sql
SELECTREGEXP_INSTR('aabbcc', 'b+', 1, 1, 1);
→-- 5
No match returns 0
sql
SELECTREGEXP_INSTR('hello', 'x');
→-- 0
⚠Anti-Pattern— Using REGEXP_INSTR where LOCATE suffices
For literal substring searches, REGEXP_INSTR adds overhead with no benefit.
✓ Instead: Use LOCATE or INSTR for literal searches; REGEXP_INSTR only when you need pattern matching.
REGEXP_INSTR returns the byte position of the first regex match. Chain it with SUBSTRING to extract the matched region when you need more control than REGEXP_SUBSTR provides — for example, when you need to find overlapping matches.
⚠Anti-Pattern— Using REGEXP_LIKE for simple prefix/suffix checks
REGEXP_LIKE(col, '^prefix') is slower and less readable than col LIKE 'prefix%'.
✓ Instead: Use LIKE for simple wildcards; reserve REGEXP_LIKE for patterns that LIKE cannot express.
REGEXP_LIKE (or the REGEXP operator) replaces long OR chains of LIKE patterns. The 'i' flag enables case-insensitive matching without changing the column collation. Use it for validation checks in CHECK constraints.
⚠Anti-Pattern— Storing Base64 in TEXT columns for binary safety
Base64 inflation means a 1 MB image becomes a 1.37 MB string, bloating row sizes and slowing queries.
✓ Instead: Use BLOB/MEDIUMBLOB columns for binary data and let the driver handle encoding.
TO_BASE64 produces the standard Base64 encoding with line breaks every 76 characters (per MIME). Use it when you must store binary data in a JSON column or email body. Remember the ~33% size overhead.
example
SELECTTO_BASE64(thumbnail) ASb64FROMmedia;
→-- '/9j/4AAQSkZJRgABAQ...'
◆MariaDB Note
Added in MariaDB 10.0.
⇄ vs MySQL: Identical to MySQL (added in MySQL 5.6 / MariaDB 10.0).
⇄ vs PostgreSQL: PostgreSQL uses ENCODE(data, 'base64') for the same purpose.
⚠Anti-Pattern— Assuming FROM_BASE64 always returns valid text
FROM_BASE64 of binary data returns raw bytes that may not be valid in the connection charset.
✓ Instead: Use CONVERT(FROM_BASE64(col) USING utf8mb4) when you know the original was UTF-8 text.
FROM_BASE64 is the inverse of TO_BASE64. Use it to decode externally encoded payloads (e.g., from APIs) before inserting into BLOB columns. It silently returns NULL for strings that are not valid Base64.
Returns a string where each bit in a numeric value maps to an 'on' or 'off' string, separated by a delimiter.
Signatures
EXPORT_SET(bits, on, off)
EXPORT_SET(bits, on, off, separator)
EXPORT_SET(bits, on, off, separator, number_of_bits)
Parameters
Parameter
Type
Description
bits
BIGINT UNSIGNED
Integer whose bits are examined
on
VARCHAR
String to use for set bits
off
VARCHAR
String to use for unset bits
separator
VARCHAR
Delimiter between values (default ',')
number_of_bits
INT
Number of bits to process (default 64)
Examples
5 = 0101 in binary
sql
SELECTEXPORT_SET(5, 'Y', 'N', ',', 4);
→-- 'Y,N,Y,N'
Binary representation
sql
SELECTEXPORT_SET(7, '1', '0', '', 4);
→-- '1110'
On a column
sql
SELECTEXPORT_SET(perms, 'R', '-', '') FROMroles;
→-- permission bitmask display
6 = 0110
sql
SELECTEXPORT_SET(6, 'on', 'off', '|', 4);
→-- 'off|on|on|off'
NULL handling
sql
SELECTEXPORT_SET(NULL, 'Y', 'N');
→-- NULL
⚠Anti-Pattern— Using EXPORT_SET as a general array-to-string function
EXPORT_SET only works with bit positions in an integer — it is not a general-purpose array serializer.
✓ Instead: Use GROUP_CONCAT or JSON_ARRAYAGG for turning row sets into delimited strings.
EXPORT_SET(bits, on, off, sep, bits_count) is the neatest way to render a bitmask as a delimited string of on/off labels. Useful for feature-flag columns, permission masks, or any integer that represents a set of boolean flags.
⚠Anti-Pattern— Using MAKE_SET with more than 64 string arguments
MAKE_SET uses a BIGINT bitmask, so it supports at most 64 bit positions.
✓ Instead: For more than 64 flags, use a SET column, JSON column, or a junction table.
MAKE_SET returns only the labels whose corresponding bit is set in the bitmask, joined by a comma by default. It's more concise than EXPORT_SET when you only want to list the active flags rather than showing Y/N for each bit.
Returns the octal string representation of a number.
Signature
OCT(n)
Parameters
Parameter
Type
Description
n
BIGINT UNSIGNED
Integer to convert to octal string
Examples
8 in octal
sql
SELECTOCT(8);
→-- '10'
255 in octal
sql
SELECTOCT(255);
→-- '377'
On a column
sql
SELECTOCT(perm_bits) FROMfiles;
→-- UNIX permission octal
Hex to octal via CONV
sql
SELECTOCT(CONV('FF', 16, 10));
→-- '377'
NULL handling
sql
SELECTOCT(NULL);
→-- NULL
⚠Anti-Pattern— Confusing octal output with a numeric value
OCT returns a VARCHAR string. Adding 1 to the result does string concatenation, not arithmetic.
✓ Instead: Use CONV() when you need to perform further arithmetic in a different base.
OCT is handy when you store Unix file permissions as integers and need to display them in the familiar octal notation. OCT(493) = '755', OCT(438) = '666'.
Returns the binary string representation of a number.
Signature
BIN(n)
Parameters
Parameter
Type
Description
n
BIGINT UNSIGNED
Integer to convert to binary string
Examples
10 in binary
sql
SELECTBIN(10);
→-- '1010'
255 in binary
sql
SELECTBIN(255);
→-- '11111111'
On a column
sql
SELECTBIN(flags) FROMsettings;
→-- binary representation of flags
Hex to binary via CONV
sql
SELECTBIN(CONV('FF', 16, 10));
→-- '11111111'
NULL handling
sql
SELECTBIN(NULL);
→-- NULL
⚠Anti-Pattern— Treating BIN output as an integer
BIN returns a VARCHAR. Arithmetic on the result treats it as a string/integer cast, not a binary number.
✓ Instead: Use CONV(BIN(n), 2, 10) to convert back to decimal, or stay in the integer domain with bitwise operators.
BIN converts an integer to its binary string representation, making it easy to visualize which bits are set in a flags or permissions column. Combine with LPAD to always show a fixed-width binary string.
⚠Anti-Pattern— Using lexicographic ORDER BY for alphanumeric data
ORDER BY filename sorts 'file10' before 'file2' because '1' < '2' lexicographically.
✓ Instead: Use ORDER BY NATURAL_SORT_KEY(filename) for human-expected ordering.
NATURAL_SORT_KEY generates a sort key that orders '10' after '9' instead of before it. This solves the classic problem where ORDER BY version_string produces 1.0, 1.10, 1.2 instead of 1.0, 1.2, 1.10.
⚠Anti-Pattern— Using LOAD_FILE with user-supplied paths
Allowing user input to control the file path is a path traversal vulnerability.
✓ Instead: Always use hard-coded or tightly validated server-side paths with LOAD_FILE.
LOAD_FILE reads a file from the server filesystem into a BLOB. It requires FILE privilege and the file must be readable by the MariaDB process. Returns NULL silently if the file doesn't exist — always check the result before inserting.
Formats a string using Python-style {} placeholder syntax (requires the fmt library).
Signature
SFORMAT(format_str, arg1, arg2, ...)
Parameters
Parameter
Type
Description
format_str
VARCHAR
Format string with {} or {:format_spec} placeholders
arg1, arg2, ...
ANY
Values substituted into the placeholders
Examples
Basic placeholder
sql
SELECTSFORMAT('Hello {}!', 'World');
→-- 'Hello World!'
Multiple placeholders
sql
SELECTSFORMAT('{} + {} = {}', 1, 2, 3);
→-- '1 + 2 = 3'
Float format spec
sql
SELECTSFORMAT('Value: {:.2f}', 3.14159);
→-- 'Value: 3.14'
From columns
sql
SELECTSFORMAT(template, val) FROMmessages;
→-- formatted messages
Positional reuse
sql
SELECTSFORMAT('Hi {0} and {0}', 'Bob');
→-- 'Hi Bob and Bob'
⚠Anti-Pattern— Using SFORMAT with untrusted format strings
Allowing user-supplied format strings could expose unexpected data or cause errors.
✓ Instead: Always use hard-coded format strings; only substitute values through the arguments.
SFORMAT is a MariaDB 10.7+ function that applies C-style format specifiers (%s, %d, %f) to build formatted strings. It's cleaner than multiple nested CONCATs for generating log messages or structured output.
example
SELECTSFORMAT('User {} logged in from {}', username, ip_address) FROMlogins;
→-- 'User alice logged in from 192.168.1.1'
◆MariaDB Note
MariaDB-specific function requiring the fmt library. Available since MariaDB 10.7.
⇄ vs MySQL: Not available in MySQL — this is a MariaDB-specific function.
⇄ vs PostgreSQL: PostgreSQL has no SFORMAT(); use FORMAT() with %s, %I, %L placeholders.
Returns the sort key (weight string) for a string value under the current collation, useful for debugging collation behavior.
Signatures
WEIGHT_STRING(str)
WEIGHT_STRING(str AS CHAR(n))
WEIGHT_STRING(str AS BINARY(n))
Parameters
Parameter
Type
Description
str
VARCHAR
String to generate the weight string for
n
INT
Cast width (optional)
Examples
Weight of lowercase a
sql
SELECTHEX(WEIGHT_STRING('a'));
→-- collation-dependent weight
Same weight under case-insensitive collation
sql
SELECTHEX(WEIGHT_STRING('A'));
→-- same as 'a' under _ci
Padded to 5 chars
sql
SELECTHEX(WEIGHT_STRING('abc'ASCHAR(5)));
→-- padded weight
Inspect sort order
sql
SELECTHEX(WEIGHT_STRING(name)) FROMtORDERBY1;
→-- collation order
NULL handling
sql
SELECTWEIGHT_STRING(NULL);
→-- NULL
⚠Anti-Pattern— Using WEIGHT_STRING in production queries for comparison
WEIGHT_STRING is a diagnostic/debugging function, not a comparison operator.
✓ Instead: Use COLLATE clauses or change column collation for production ordering and comparison needs.
WEIGHT_STRING returns the binary sort key used by a collation, allowing you to see exactly why two strings sort the way they do. It's primarily a diagnostic tool for collation troubleshooting.
Converts a value to a different data type or character set.
Signatures
CONVERT(value, type)
CONVERT(value USING charset_name)
Parameters
Parameter
Type
Description
value
ANY
Value to convert
type
TYPE
Target data type (e.g. CHAR, SIGNED, UNSIGNED, BINARY)
charset_name
VARCHAR
Target character set for the USING form
Examples
String to integer
sql
SELECTCONVERT('123', SIGNED);
→-- 123
Re-encode charset
sql
SELECTCONVERT('hello'USINGutf8mb4);
→-- 'hello' in utf8mb4
Float to string
sql
SELECTCONVERT(3.14, CHAR);
→-- '3.14'
Binary to text
sql
SELECTCONVERT(UNHEX('41') USINGutf8mb4);
→-- 'A'
NULL handling
sql
SELECTCONVERT(NULL, CHAR);
→-- NULL
⚠Anti-Pattern— Using CONVERT to cast in arithmetic instead of CAST
CONVERT(str, SIGNED) and CAST(str AS SIGNED) are equivalent, but mixing both in a codebase is confusing.
✓ Instead: Standardize on CAST() for type conversions and CONVERT(...USING...) for charset conversions.
CONVERT(col USING utf8mb4) recodes a string at query time without altering the stored value. Use it when comparing columns with different character sets to avoid 'Illegal mix of collations' errors.
⚠Anti-Pattern— Using DECODE/ENCODE for production security
ENCODE/DECODE are not cryptographically secure and are deprecated in MariaDB.
✓ Instead: Use AES_ENCRYPT() / AES_DECRYPT() with AES_256_CBC mode and a strong key for real encryption.
In MariaDB, DECODE(str, pass) is a synonym for AES_DECRYPT with some Oracle-compatibility behavior. For new code, use AES_DECRYPT explicitly to make the intent clear and to control the encryption mode.
Encrypts a string using a password with a simple XOR-based algorithm (deprecated; not cryptographically secure).
Signature
ENCODE(str, pass_str)
Parameters
Parameter
Type
Description
str
VARCHAR
String to encrypt
pass_str
VARCHAR
Password string
Examples
Encode and view as hex
sql
SELECTHEX(ENCODE('hello', 'key'));
→-- hex of encrypted bytes
On a column
sql
SELECTENCODE(sensitive, 'pass') FROMdata;
→-- encrypted VARBINARY
Same length as input
sql
SELECTOCTET_LENGTH(ENCODE('test', 'pw'));
→-- 4
Round-trip
sql
SELECTDECODE(ENCODE('msg', 'k'), 'k');
→-- 'msg'
NULL handling
sql
SELECTENCODE(NULL, 'key');
→-- NULL
⚠Anti-Pattern— Storing ENCODE output in a VARCHAR column
ENCODE returns binary data that may contain null bytes, which truncates VARCHAR storage.
✓ Instead: Store ENCODE output in a VARBINARY or BLOB column, or better yet use AES_ENCRYPT.
ENCODE(str, pass) is a weak obfuscation alias deprecated in MariaDB 10.3. It should never be used for real security. Replace all ENCODE calls with AES_ENCRYPT(str, key, iv) using a secure AES-256 mode.