Skip to content

Instantly share code, notes, and snippets.

@jrunning
Last active August 11, 2020 08:41
Show Gist options
  • Save jrunning/4535434 to your computer and use it in GitHub Desktop.
Save jrunning/4535434 to your computer and use it in GitHub Desktop.
MySQL COALESCE() silently casts its return to the type of subsequent non-NULL arguments
-- The MySQL docs say COALESCE() "returns the first non-NULL value in the list,
-- or NULL if there are no non-NULL values." This turns out not to be true.
-- If the value to be returned is an integer, COALESCE() first casts it to
-- the type of a subsequent non-NULL argument. ಠ_ಠ
mysql> SELECT 0 = '',
-> COALESCE(0, '') = '',
-> COALESCE(0, ''),
-> COALESCE(0, NULL),
-> COALESCE(0, 98.6, NULL),
-> COALESCE(0, 50) = ''
-> ;
+--------+----------------------+-----------------+-------------------+-------------------------+----------------------+
| 0 = '' | COALESCE(0, '') = '' | COALESCE(0, '') | COALESCE(0, NULL) | COALESCE(0, 98.6, NULL) | COALESCE(0, 50) = '' |
+--------+----------------------+-----------------+-------------------+-------------------------+----------------------+
| 1 | 0 | 0 | 0 | 0.0 | 1 |
+--------+----------------------+-----------------+-------------------+-------------------------+----------------------+
-- ^---(string) (integer) ---^
mysql> SELECT COALESCE('99', 0),
-> COALESCE(99, '0')
-> ;
+-------------------+-------------------+
| COALESCE('99', 0) | COALESCE(99, '0') |
+-------------------+-------------------+
| 99 | 99 |
+-------------------+-------------------+
-- ^---(string) ^---(string)
mysql> SELECT COALESCE(1, 99),
-> COALESCE(1, 99.0),
-> COALESCE(1, 99.0, 99),
-> COALESCE(1, 99, '99'),
-> COALESCE(1, '99', 99)
-> ;
+-----------------+-------------------+-----------------------+-----------------------+-----------------------+
| COALESCE(1, 99) | COALESCE(1, 99.0) | COALESCE(1, 99.0, 99) | COALESCE(1, 99, '99') | COALESCE(1, '99', 99) |
+-----------------+-------------------+-----------------------+-----------------------+-----------------------+
| 1 | 1.0 | 1.0 | 1 | 1 |
+-----------------+-------------------+-----------------------+-----------------------+-----------------------+
-- (integer)---^ ^---(string) ^---(string)
@jrunning
Copy link
Author

COALESCE() turns out to be syntactic sugar for a CASE expression, for which the docs say, "The return type of a CASE expression is the compatible aggregated type of all return values." Good luck finding a definition for that, but it more or less means that it looks at all of the possible return values and picks whatever type they can all be represented in. Other RDBMSes document their "type precedence" but I can't find any such documentation for MySQL.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment