25. Collations
A collation determines how two texts are compared: equality, ordering, GROUP BY, DISTINCT, PRIMARY / UNIQUE keys, joins, LIKE, partitions and full-text search. Miraj offers three, chosen per column, per table or per expression, following the rules of the reference. All text is stored as UTF-8 (utf8mb4).
25.1 The three collations#
| Collation | Accepted SQL names | Behavior |
|---|---|---|
| general (default) | utf8mb4_general_ci, utf8mb3_general_ci (utf8_general_ci), latin1_swedish_ci, latin1_general_ci | one 16-bit weight per character; case and accents ignored ('Crème' = 'creme'), ß = s (but ≠ ss), æ, œ, ø, ł keep their own weight; every character outside the BMP weighs U+FFFD ('😀' = '😁') |
| Unicode | utf8mb4_unicode_ci, utf8mb3_unicode_ci (utf8_unicode_ci), and approximately utf8mb4_unicode_520_ci, utf8mb3_unicode_520_ci, utf8mb4_uca1400_ai_ci, utf8mb3_uca1400_ai_ci | UCA 4.0.0 table taken from the reference, primary level only: case and accents ignored, expansions ('ß' = 'ss', 'œ' = 'oe', 'fi' = 'fi', 'Ⅳ' = 'iv'), combining marks and control characters ignored ('e' + U+0301 = 'e'), æ remains a letter of its own ('æ' ≠ 'ae'); UCA order (punctuation < digits < letters: '_' < 'a'); ideographs and characters absent from the table: implicit weights; every character outside the BMP has the same weight ('😀' = '😁') |
| binary | utf8mb4_bin, utf8mb3_bin (utf8_bin), latin1_bin | comparison by code point: case and accents distinguished ('A1' ≠ 'a1', 'é' ≠ 'e'), 'B' < 'a' |
All three are PAD SPACE: trailing spaces (U+0020 only) are ignored by =, ordering, GROUP BY, DISTINCT, keys and joins ('a' = 'a ' is 1, even in binary; a trailing tab counts). LIKE never pads with spaces ('a ' LIKE 'a' is false).
The utf8_… aliases are read as utf8mb3_…. CHARACTER SET latin1 is accepted for a column but the text is still stored as utf8mb4. The binary type (BINARY, VARBINARY, BLOB, CAST(… AS BINARY)) is always compared byte by byte, without PAD.
A JSON column is always utf8mb4_bin (as on the reference): two documents that differ only in case are different, and JSON_UNQUOTE(JSON_EXTRACT(doc, '$.a')) = 'x' does not find "X". SHOW CREATE TABLE writes nothing for it.
25.2 Choosing the collation#
Column and table#
CREATE TABLE liasse (
code VARCHAR(10) COLLATE utf8mb4_bin PRIMARY KEY, -- 'A1' and 'a1' are two codes
nom VARCHAR(80) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci,
notes TEXT -- table default
) DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;[CHARACTER SET set] COLLATE nameafter the type of a text column (CHAR,VARCHAR,*TEXT,ENUM,SET);CHARACTER SET setalone gives the default collation of the set, the general collation.- The
BINARYattribute of a text column (VARCHAR(10) BINARY) is equivalent toCOLLATE utf8mb4_bin;BINARY COLLATEwith any other name: error 1302. [DEFAULT] CHARSET = set,[DEFAULT] COLLATE = nameas a table option: default for text columns written without a collation.CREATE TABLE … LIKEcopies columns and default;CREATE TABLE … AS SELECTand view columns take the collation of the source column or expression (CONCAT(col_bin, 'x')stays binary).
ALTER TABLE#
MODIFY/CHANGE/ADDof a column: theCOLLATEwritten, otherwise the table default;RENAME COLUMNkeeps the collation.[DEFAULT] COLLATE = namechanges the table default without touching existing columns.CONVERT TO CHARACTER SET utf8mb4 [COLLATE name]converts all text columns (exceptJSON).- Changing the collation of a key column rechecks the key: values that have become equal (
'A1'and'a1'going from binary to general,'ß'and'ss'going to Unicode) give 1062 and the table is left unchanged. - Changing the collation of a partitioning column is refused (1235).
Expression#
expr COLLATE name imposes a collation on a text expression:
SELECT 'a' COLLATE utf8mb4_bin = 'A'; -- 0
SELECT * FROM clients WHERE nom = 'strasse' COLLATE utf8mb4_unicode_ci; -- finds « Straße »
SELECT code FROM liasse ORDER BY code COLLATE utf8mb4_general_ci;The name must be a utf8mb4 collation ('a' COLLATE utf8_bin or COLLATE latin1_bin: 1253); COLLATE binary: 1064.
25.3 Coercibility: which collation wins#
When two texts meet (=, <, IN, BETWEEN, CASE, LIKE, STRCMP, LOCATE, join, UNION, CONCAT…), each carries a coercibility; the lowest wins:
| Coercibility | Value | Examples |
|---|---|---|
EXPLICIT | 0 | expr COLLATE name |
NONE | 1 | CONCAT(col_unicode, col_general): a mix with no winner |
IMPLICIT | 2 | table, view or derived table column |
SYSCONST | 3 | USER(), DATABASE(), VERSION(), @@variable |
CAST | 4 | CAST(… AS CHAR), CONVERT(… USING utf8mb4) |
USERVAR | 5 | @v |
COERCIBLE | 6 | literal, parameter, function with no text argument (HEX, DATE_FORMAT) |
NUMERIC / IGNORABLE | 7 / 8 | numbers, dates, NULL: take no part |
- Column against literal: the column wins (
WHERE code = 'a1'on a binary column does not return'A1'); an explicitCOLLATEwins over the column. - With equal coercibility and different collations: binary wins (binary column against general column in an
ON: binary comparison); general against Unicode: error 1267; two different explicitCOLLATEs: 1267. - An operation with three operands and no winner (
u IN (g, 'x'),CASE): 1270; four or more: 1271 (UNION: 1271 for any mix with no winner). CONCAT,COALESCE,IF… with arguments that have no winner return(utf8mb4_bin, NONE): their result can no longer be compared to a literal (1267).
25.4 Functions and operators#
| Operation | Collation applied |
|---|---|
=, <, <=>, IN, BETWEEN, CASE, NULLIF, LEAST, GREATEST, STRCMP, FIELD, FIND_IN_SET | resolved collation of the operands |
GROUP BY, DISTINCT, COUNT(DISTINCT), MIN / MAX, ORDER BY, window functions, joins, UNION | that of the expression |
LIKE | resolved on the value and the pattern; character against character, without PAD and without expansion ('ß' LIKE 'ss' is false in Unicode, 'Crème' LIKE 'Cr_me' true everywhere, LIKE 'crème' false in binary) |
LOCATE, INSTR, POSITION | general: case-insensitive, accent-sensitive; Unicode and binary: window of the same byte length as the substring (LOCATE('ss', 'Straße' COLLATE utf8mb4_unicode_ci) returns 5, LOCATE('a', 'A' COLLATE utf8mb4_bin) returns 0) |
REGEXP, REGEXP_* | no weights ('é' REGEXP 'e' false); case-insensitive except in binary ('ABC' COLLATE utf8mb4_bin REGEXP 'abc' is 0); the 'c' / 'i' match type wins |
REPLACE, TRIM, SUBSTRING_INDEX | binary (case-sensitive) search in all three cases; incompatible collations: 1267 / 1270 |
WEIGHT_STRING | that of the first argument: general 16 bits per character, Unicode 16 bits per weight unit (AS CHAR(n) cuts at n units, pads with 0209), binary 3 bytes per character (padded with 000020) |
JSON_SEARCH | that of the document (JSON column: binary; literal: general; text column: its own) |
MATCH … AGAINST | that of the FULLTEXT index: 'strasse' finds Straße in Unicode, binary distinguishes case and accents |
UPPER and LOWER remain Unicode case mappings whatever the collation.
25.5 Indexes, keys and partitions#
Primary and UNIQUE keys, secondary indexes, foreign keys, trigram and FULLTEXT indexes, and partition bounds and lists follow the collation of their column: in binary 'A1' and 'a1' are two keys, in Unicode 'ß' and 'ss' make only one (1062). An index serves a condition only if the resolved collation of the condition is that of the column: WHERE code COLLATE utf8mb4_general_ci = 'a1' reads the whole table. A FULLTEXT index on columns with different collations: 1283.
25.6 Metadata#
SHOW CREATE TABLEwritesCHARACTER SET utf8mb4 COLLATE nameafter the type of a column whose collation differs from the table default, andDEFAULT CHARSET=utf8mb4 COLLATE=namewhen the table default is not the general collation.SHOW FULL COLUMNS(Collationcolumn),information_schema.COLUMNS.COLLATION_NAME,TABLES.TABLE_COLLATION.SHOW COLLATIONandinformation_schema.COLLATIONS: three rows,utf8mb4_general_ci(45, default),utf8mb4_bin(46),utf8mb4_unicode_ci(224), allPAD SPACE; aliases are not listed.- Protocol: a Unicode or binary result column is announced as 224 or 46; a general column, like a
JSONcolumn, is still announced as 33.
25.7 Errors#
| Code | Case |
|---|---|
| 1062 | duplicate under the key's collation (also on the ALTER that changes the collation) |
| 1064 | COLLATE binary on a text |
| 1235 | changing the collation of a partitioning column; ALTER DATABASE … COLLATE |
| 1253 | collation of another character set (CHARACTER SET latin1 COLLATE utf8mb4_unicode_ci, 'a' COLLATE utf8_bin) |
| 1267 | two operands with no winner: Illegal mix of collations (utf8mb4_unicode_ci,IMPLICIT) and (utf8mb4_general_ci,IMPLICIT) for operation '=' |
| 1270 | three operands with no winner (IN, CASE, REPLACE) |
| 1271 | four or more operands, or UNION |
| 1273 | unknown name: Unknown collation: 'utf8mb4_0900_ai_ci' |
| 1283 | FULLTEXT on columns with different collations |
| 1302 | BINARY and a non-binary COLLATE on the same column |
25.8 Differences and out of scope#
utf8mb4_unicode_520_ciandutf8mb4_uca1400_ai_ciare filed under Unicode (4.0.0 table): on the reference their weights differ (characters added after Unicode 4.0, emojis distinct from one another), and comparingunicode_citounicode_520_cithere gives 1267 (Miraj: no error).CHARACTER SET utf8mb4alone,CAST(… AS CHAR)andCONVERT(… USING utf8mb4)give the general collation; the recent reference usesuca1400_ai_cithere.- Not yet supported: default collation of a database (
CREATE DATABASE … COLLATE, accepted with no effect),SET NAMES … COLLATEandcollation_connection(no effect), collation of a user variable (SET @v = x COLLATE …:@vstays general), ofNEW.col/OLD.colin a trigger and of routine variables (compared as general literals). CHARSET(),COLLATION()andCOERCIBILITY()are available (chapter 8, §8.9): they return the character set, collation and coercibility (0 to 8) of the expression as the engine resolves it,binaryfor a number, a date orNULL,latin1/latin1_swedish_ciorutf8mb3forCONVERT(… USING set).- Out of scope:
NO PADcollations, case- or accent-sensitive collations other than binary (*_as_cs,*_ai_cs), language-specific ones (german2,czech,turkish…),utf8mb4_0900_*: 1273. - Existing databases: any table created before collations were introduced is read with the general collation, indexes and partitions unchanged; only a deliberate
ALTER TABLE … COLLATEchanges it.