MariaDB Control Flow Functions — IF, CASE, COALESCE
MariaDB
Complete reference for MariaDB control flow functions covering IF, CASE, COALESCE, IFNULL, NULLIF, NVL, NVL2, and DECODE_ORACLE. Every function includes syntax, NULL-handling examples, and comparisons with MySQL and PostgreSQL conditional expressions. Updated for MariaDB 11.x.
What are MariaDB Control Flow Functions — IF, CASE, COALESCE?
MariaDB control flow functions handle conditional branching and NULL substitution in SQL queries. COALESCE() returns the first non-NULL argument, IF(condition, true_val, false_val) is a shorthand ternary, and IFNULL() is the two-argument NULL coalescing shortcut. MariaDB adds Oracle compatibility functions NVL() and NVL2() in SQL_MODE=ORACLE, and DECODE_ORACLE() provides Oracle-style DECODE(). These functions differ from PostgreSQL's COALESCE and CASE in minor syntax details but are conceptually equivalent.
IF
MariaDB 5.5+→ ANY (type of true_value or false_value)
Returns true_value if condition is true (non-zero and non-NULL), otherwise returns false_value.
Signature
IF(condition, true_value, false_value)
Parameters
Parameter
Type
Description
condition
BOOLEAN / numeric
Expression evaluated as true (non-zero, non-NULL) or false
Nesting multiple IF() calls to handle several conditions becomes unreadable quickly.
✓ Instead: Use CASE WHEN ... THEN ... ELSE ... END for three or more branches — it is far more readable and maintainable.
IF() is concise for a single true/false condition. Nesting multiple IF() calls is error-prone and hard to read. As soon as you have three or more branches, switch to a CASE WHEN expression — it is more readable and equally fast.
Returns expr if it is not NULL; otherwise returns fallback. Equivalent to COALESCE(expr, fallback) with exactly two arguments.
Signature
IFNULL(expr, fallback)
Parameters
Parameter
Type
Description
expr
ANY
Expression to test for NULL
fallback
ANY
Value returned when expr is NULL
Examples
NULL replaced by fallback
sql
SELECTIFNULL(NULL, 'default');
→-- default
Non-NULL returned as-is
sql
SELECTIFNULL('value', 'default');
→-- value
Replace NULL column
sql
SELECTIFNULL(middle_name, '') FROMcustomers;
→-- middle name or empty string
0 is not NULL
sql
SELECTIFNULL(0, 99);
→-- 0
Column fallback
sql
SELECTIFNULL(price, list_price) FROMproducts;
→-- price or list_price
⚠Anti-Pattern— Using IFNULL on aggregates without considering GROUP BY
SELECT IFNULL(SUM(amount), 0) looks safe, but SUM() over an empty set already returns NULL — make sure you actually need the IFNULL wrapper, and be aware it does not change row counts.
✓ Instead: Use COALESCE(SUM(amount), 0) which is more portable and equally clear.
IFNULL(a, b) is equivalent to COALESCE(a, b) but only accepts exactly two arguments. When you need more than one level of fallback (e.g., price → list_price → 0), use COALESCE which is more readable and avoids nested IFNULL calls.
Returns NULL if expr1 equals expr2; otherwise returns expr1. Useful for preventing division-by-zero and converting sentinel values to NULL.
Signature
NULLIF(expr1, expr2)
Parameters
Parameter
Type
Description
expr1
ANY
Primary expression; returned when the two arguments differ
expr2
ANY
Comparison value; when equal to expr1 the result is NULL
Examples
Equal values return NULL
sql
SELECTNULLIF(5, 5);
→-- NULL
Unequal values return expr1
sql
SELECTNULLIF(5, 3);
→-- 5
Division-by-zero guard
sql
SELECT100/NULLIF(divisor, 0) FROMmetrics;
→-- NULL instead of divide-by-zero error
Sentinel to NULL
sql
SELECTNULLIF(status, 'N/A') FROMrecords;
→-- NULL when status is 'N/A'
NULL = NULL comparison still yields NULL
sql
SELECTNULLIF(NULL, NULL);
→-- NULL
⚠Anti-Pattern— Expecting NULLIF to act like IFNULL
NULLIF produces NULL when values match; IFNULL replaces NULL with a fallback. Mixing them up inverts your logic.
✓ Instead: Use NULLIF to convert a value TO NULL, and IFNULL/COALESCE to convert FROM NULL.
NULLIF(denominator, 0) returns NULL when the denominator is zero, which propagates NULL through the division safely — no divide-by-zero error, no special CASE needed. This is the idiomatic guard for ratio calculations.
IFNULL(a, b) only accepts two arguments; COALESCE accepts any number. Nesting IFNULL(IFNULL(a, b), c) is harder to read than COALESCE(a, b, c).
✓ Instead: Use COALESCE when you have more than two fallback values.
COALESCE evaluates arguments left-to-right and stops at the first non-NULL. Place the column or expression most likely to be non-NULL first, and expensive subqueries or function calls last, to minimize evaluation cost.
MariaDB 5.5+→ ANY (type of matched THEN value or ELSE value)
Conditional expression with two forms: simple CASE compares an expression against fixed values; searched CASE evaluates arbitrary boolean conditions. Returns the value of the first matching THEN clause, or the ELSE value (NULL if ELSE is omitted).
Signatures
CASE expr WHEN val1 THEN result1 [WHEN val2 THEN result2 ...] [ELSE default] END
CASE WHEN condition1 THEN result1 [WHEN condition2 THEN result2 ...] [ELSE default] END
Parameters
Parameter
Type
Description
expr
ANY
Expression compared against WHEN values (simple form only)
condition
BOOLEAN
Boolean expression evaluated for each WHEN clause (searched form)
result
ANY
Value returned for a matching WHEN branch
default
ANY
Value returned when no WHEN matches; NULL if ELSE is omitted
⚠Anti-Pattern— Omitting ELSE and ignoring the implicit NULL
When no WHEN clause matches and ELSE is absent, CASE returns NULL silently. This can cause unexpected NULLs to propagate through calculations.
✓ Instead: Always include an ELSE clause, even if just ELSE NULL, to make the intent explicit and prevent surprises.
CASE WHEN ... THEN ... ELSE ... END is standard SQL and behaves identically in MariaDB, MySQL, PostgreSQL, SQLite, and SQL Server. Prefer it over vendor-specific IF() when writing portable application queries or when more than two branches are needed.
MariaDB 10.3.2+→ ANY (type of true_value or false_value)
Returns true_value if condition is true (non-zero and non-NULL), otherwise returns false_value. IIF is an alias for IF() introduced in MariaDB 10.3.2 for compatibility with Microsoft SQL Server and Access.
Signature
IIF(condition, true_value, false_value)
Parameters
Parameter
Type
Description
condition
BOOLEAN / numeric
Expression evaluated as true (non-zero, non-NULL) or false
true_value
ANY
Value returned when condition is true
false_value
ANY
Value returned when condition is false or NULL
Examples
Identical to IF(1>0,'yes','no')
sql
SELECTIIF(1>0, 'yes', 'no');
→-- yes
Column-based branch
sql
SELECTIIF(stock>0, 'In Stock', 'Out of Stock') FROMproducts;
⚠Anti-Pattern— Using IIF expecting it to work in MySQL
IIF() does not exist in MySQL; using it makes your SQL incompatible with plain MySQL deployments.
✓ Instead: Use IF() for MySQL-compatible code, or CASE WHEN for maximum portability.
IIF(cond, a, b) in MariaDB is a direct alias for IF(cond, a, b). When porting queries from SQL Server or Access that heavily use IIF(), this saves replacing every occurrence. For new MariaDB code, IF() or CASE WHEN is more familiar to most developers.
Returns expr if it is not NULL; otherwise returns fallback. Equivalent to IFNULL() and provided as an Oracle compatibility alias in MariaDB 10.3+.
Signature
NVL(expr, fallback)
Parameters
Parameter
Type
Description
expr
ANY
Expression to test for NULL
fallback
ANY
Value returned when expr is NULL
Examples
NULL replaced by fallback
sql
SELECTNVL(NULL, 'default');
→-- default
Non-NULL returned as-is
sql
SELECTNVL('value', 'default');
→-- value
Oracle-style NULL guard
sql
SELECTNVL(commission, 0) FROMemployees;
→-- commission or 0
Column fallback chain
sql
SELECTNVL(phone, email) FROMcontacts;
→-- phone or email
0 is not NULL
sql
SELECTNVL(0, 99);
→-- 0
⚠Anti-Pattern— Using NVL in code that must also run on MySQL
NVL() does not exist in MySQL. Code using it will fail on a standard MySQL server.
✓ Instead: Use IFNULL(expr, fallback) which works on both MariaDB and MySQL.
NVL(a, b) is a MariaDB Oracle-compatibility function identical to IFNULL(a, b). Code using NVL will fail on plain MySQL. If your application needs to run on both MariaDB and MySQL, use IFNULL which is supported by both.
MariaDB 10.3+→ ANY (type of not_null_value or null_value)
Returns not_null_value if expr is not NULL; returns null_value if expr is NULL. An Oracle compatibility function added in MariaDB 10.3. Extends NVL by allowing a different return value for both the NULL and non-NULL cases.
⚠Anti-Pattern— Expecting NVL2 argument order to match IF()
IF(condition, true_val, false_val) and NVL2(expr, not_null_val, null_val) share the same argument order (true branch second, false branch third), but NVL2's first argument is an expression tested for NULL, not a boolean. Passing a boolean condition to NVL2 evaluates whether that expression is NULL or not — usually not what you want.
✓ Instead: Use IF(expr IS NULL, null_val, not_null_val) or CASE WHEN to make the NULL check explicit.
NVL2(expr, a, b) returns a when expr is not NULL and b when expr is NULL. It is more concise than CASE WHEN expr IS NOT NULL THEN a ELSE b END. Use it only in MariaDB/Oracle contexts since it is not available in MySQL.
MariaDB 10.3+ (Oracle mode)→ ANY (type of matched return value or default)
Compares expr against a series of search values and returns the corresponding result for the first match. An optional final argument serves as the default when no match is found. Available in MariaDB 10.3+ under Oracle SQL mode. NULL-safe: NULL = NULL is treated as a match.
⚠Anti-Pattern— Confusing MariaDB DECODE with MySQL DECODE
MySQL has a DECODE(ciphertext, key) function that decrypts DES-encrypted data — completely different from Oracle/MariaDB DECODE. Using Oracle-style DECODE in MySQL will produce wrong results silently.
✓ Instead: In MySQL, use CASE WHEN. In MariaDB with Oracle mode, DECODE(expr, ...) works as the Oracle-compatible conditional.
MariaDB's DECODE(expr, s1, r1, s2, r2, default) is a conditional expression matching Oracle's DECODE. MySQL's DECODE(ciphertext, key) is a DES decryption function. Never confuse them in cross-database code.
Requires sql_mode=ORACLE or the Oracle compatibility plugin in MariaDB 10.3+.
⇄ vs MySQL: MySQL DECODE(ciphertext, key) is a DES decryption function — completely different. The Oracle-compatible conditional DECODE does not exist in MySQL.
⇄ vs PostgreSQL: PostgreSQL has no DECODE() conditional; use CASE WHEN. (PostgreSQL does have decode() for binary encoding, unrelated.)
⚠Anti-Pattern— Using GREATEST as a MAX() replacement across rows
GREATEST operates across columns within a single row, not across multiple rows. MAX() aggregates across rows.
✓ Instead: Use MAX(column) to find the largest value across rows; use GREATEST(col1, col2) to find the largest value across columns in the same row.
GREATEST returns NULL if any argument is NULL. When comparing columns that might be NULL (e.g., a nullable bonus column vs a base salary), wrap nullable arguments in COALESCE with an appropriate sentinel to get the correct greatest value.
⚠Anti-Pattern— Confusing LEAST with MIN() aggregate
LEAST compares values across columns in the same row; MIN() aggregates across rows. They are not interchangeable.
✓ Instead: Use MIN(column) to find the smallest value across rows; use LEAST(col1, col2) to find the smaller of two columns in the same row.
Like GREATEST, LEAST propagates NULL from any argument. Use COALESCE with a large sentinel value (like 9999999) on nullable arguments so the LEAST comparison ignores missing values rather than always returning NULL.
⚠Anti-Pattern— Comparing ISNULL result with = instead of using it as a boolean
Writing WHERE ISNULL(col) = 1 is redundant. The function already returns 1 or 0.
✓ Instead: Write WHERE ISNULL(col) or, more readably, WHERE col IS NULL.
ISNULL() is a function returning 0 or 1, while IS NULL is a predicate that can use NULL-optimized index scans. Both work correctly but IS NULL reads more naturally in WHERE clauses and is portable to all SQL databases.