本文為mariadb官方手冊:SETTING CHARACTER SETS AND COLLATIONS的譯文。 原文:https://mariadb.com/kb/en/setting-character-sets-and-collations/我提交到MariaDB官方手冊的譯文:https:/ ...
本文為mariadb官方手冊:SETTING CHARACTER SETS AND COLLATIONS的譯文。
原文:https://mariadb.com/kb/en/setting-character-sets-and-collations/
我提交到MariaDB官方手冊的譯文:https://mariadb.com/kb/zh-cn/setting-character-sets-and-collations/
在MariaDB中,預設的字元集character set為latin1,預設的排序規則為latin1_swedish_ci(但不同的發行版可能會不同,例如Debian)。字元集和排序規則都可以從server端一直指定到欄位級別,client連接到server時也可以指定。當修改字元集但卻沒有指定排序規則時,將總是使用字元集的預設排序規則。
字元集和排序規則總是級聯向下的,所以當沒有為欄位指定排序規則時,將查找表的排序規則,同樣對於表來說會上查到資料庫,對資料庫來說會上查到server級。因此,可以使用極細粒度的字元集和排序規則來控制控制你的數據。
每種字元集的預設排序規則可使用SHOW COLLATION語句查看,例如查找latin2字元集的預設排序規則:
SHOW COLLATION LIKE 'latin2%';
+---------------------+---------+----+---------+----------+---------+
| Collation | Charset | Id | Default | Compiled | Sortlen |
+---------------------+---------+----+---------+----------+---------+
| latin2_czech_cs | latin2 | 2 | | Yes | 4 |
| latin2_general_ci | latin2 | 9 | Yes | Yes | 1 |
| latin2_hungarian_ci | latin2 | 21 | | Yes | 1 |
| latin2_croatian_ci | latin2 | 27 | | Yes | 1 |
| latin2_bin | latin2 | 77 | | Yes | 1 |
+---------------------+---------+----+---------+----------+---------+
Server級別
可以設置系統變數character_set_server來改變預設的server級的字元集。該變數可以使用SET命令在啟動時或動態地設置:
SET character_set_server = 'latin2';
類似地,變數collation_server用於設置server級別的預設排序規則。
SET collation_server = 'latin2_czech_cs';
Database級別
CREATE DATABASE 和 ALTER DATABASE 語句中包含了可選的字元集、排序規則的設置子句。如果沒有設置字元集、排序規則,它們將使用server級別的預設值。
CREATE DATABASE czech_slovak_names
CHARACTER SET = 'keybcs2'
COLLATE = 'keybcs2_bin';
ALTER DATABASE czech_slovak_names COLLATE = 'keybcs2_general_ci';
使用下麵的語句可以查看資料庫所使用的字元集:
SHOW CREATE DATABASE czech_slovak_names;
+--------------------+--------------------------------------------------------------------------------+
| Database | Create Database |
+--------------------+--------------------------------------------------------------------------------+
| czech_slovak_names | CREATE DATABASE `czech_slovak_names` /*!40100 DEFAULT CHARACTER SET keybcs2 */ |
+--------------------+--------------------------------------------------------------------------------+
或者,使用下麵的語句可以查看各資料庫採用的字元集和排序規則:
SELECT * FROM INFORMATION_SCHEMA.SCHEMATA;
+--------------+--------------------+----------------------------+------------------------+----------+
| CATALOG_NAME | SCHEMA_NAME | DEFAULT_CHARACTER_SET_NAME | DEFAULT_COLLATION_NAME | SQL_PATH |
+--------------+--------------------+----------------------------+------------------------+----------+
| def | czech_slovak_names | keybcs2 | keybcs2_general_ci | NULL |
| def | information_schema | utf8 | utf8_general_ci | NULL |
| def | mysql | latin1 | latin1_swedish_ci | NULL |
| def | performance_schema | utf8 | utf8_general_ci | NULL |
| def | test | latin1 | latin1_swedish_ci | NULL |
+--------------+--------------------+----------------------------+------------------------+----------+
可以僅指定排序規則,由於每種排序規則都對應於一種字元集,因此會同時設置排序規則所對應的字元集。
CREATE DATABASE danish_names COLLATE 'utf8_danish_ci';
SHOW CREATE DATABASE danish_names;
+--------------+----------------------------------------------------------------------------------------------+
| Database | Create Database |
+--------------+----------------------------------------------------------------------------------------------+
| danish_names | CREATE DATABASE `danish_names` /*!40100 DEFAULT CHARACTER SET utf8 COLLATE utf8_danish_ci */ |
+--------------+----------------------------------------------------------------------------------------------+
儘管可以動態地設置系統變數character_set_database和collation_database,但它們用於確定資料庫所使用的預設字元集和排序規則,應該儘量僅在server端進行設置。
Table級別
CREATE TABLE 和 ALTER TABLE 語句支持可選的字元集、排序規則設置子句,它們是MariaDB和MySQL對標準SQL語句的擴展。
CREATE TABLE english_names (id INT, name VARCHAR(40))
CHARACTER SET 'utf8'
COLLATE 'utf8_icelandic_ci';
如果既沒有指定字元集也沒有指定排序規則,則採用資料庫的預設值。如果僅設置了字元集,將採用字元集的預設排序規則。如果僅設置了排序規則,則排序規則相關聯的字元集也會被設置。
ALTER TABLE table_name
CONVERT TO CHARACTER SET charset_name [COLLATE collation_name];
如果沒有指定排序規則,將使用字元集預設的排序規則。
對於VARCHAR或TEXT類型的欄位,為了保證新欄位足夠大以能夠存儲原欄位的大量字元,CONVERT TO CHARACTER SET可能會改變數據類型。
例如,某TEXT類型的欄位存儲ascii字元時由於每個字元僅占用一個位元組,因此該欄位可以存儲65,535個字元。如果該欄位轉換為UTF8,由於每個字元需要3個位元組,該欄位的數據類型將被轉換為MEDIUMTEXT類型以便能夠存儲所有原欄位的字元。
CONVERT TO CHARACTER SET binary將分別轉換CHAR、VARCHAR和TEXT欄位為BINARY、VARBINARY和BLOB,並且之後將不再具有字元集屬性,或者可以在以後使用CONVERT TO CHARACTER SET語句來改變該行為。
為了避免CONVERT TO CHARACTER SET子句改變數據類型,可以在單獨的欄位上使用MODIFY。例如:
ALTER TABLE table_name MODIFY ascii_text_column TEXT CHARACTER SET utf8;
ALTER TABLE table_name MODIFY ascii_varchar_column VARCHAR(M) CHARACTER SET utf8;
Column級別
同樣可以為欄位類型為CHAR、TEXT或VARCHAR的欄位設置字元集和排序規則。可以使用CREATE TABLE和ALTER TABLE語句進行設置——不像table級別的設置,column級別的設置是標準SQL所支持的。
CREATE TABLE european_names (
croatian_names VARCHAR(40) COLLATE 'cp1250_croatian_ci',
greek_names VARCHAR(40) CHARACTER SET 'greek');
如果既沒有指定字元集也沒有指定排序規則,將使用表的預設值。如果僅設置了字元集,排序規則將使用字元集的預設排序規則,如果僅設置了排序規則,則其對應的字元集也會被設置。
當使用ALTER TABLE改變欄位的字元集時,需要確保字元集可以和已有數據相容。MariaDB將儘可能地一一映射轉換字元數據,但無法轉換的數據可能會亂碼丟失。 可以使用SHOW CREATE TABLE語句,或者查詢INFORMATION_SCHEMA資料庫來查看欄位的字元集和排序規則所採用的值。
SHOW CREATE TABLE european_names\G
*************************** 1. row ***************************
Table: european_names
Create Table: CREATE TABLE `european_names` (
`croatian_names` varchar(40) CHARACTER SET cp1250 COLLATE cp1250_croatian_ci DEFAULT NULL,
`greek_names` varchar(40) CHARACTER SET greek DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_danish_ci
SELECT * FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME LIKE 'european%'\G
*************************** 1. row ***************************
TABLE_CATALOG: def
TABLE_SCHEMA: danish_names
TABLE_NAME: european_names
COLUMN_NAME: croatian_names
ORDINAL_POSITION: 1
COLUMN_DEFAULT: NULL
IS_NULLABLE: YES
DATA_TYPE: varchar
CHARACTER_MAXIMUM_LENGTH: 40
CHARACTER_OCTET_LENGTH: 40
NUMERIC_PRECISION: NULL
NUMERIC_SCALE: NULL
DATETIME_PRECISION: NULL
CHARACTER_SET_NAME: cp1250
COLLATION_NAME: cp1250_croatian_ci
COLUMN_TYPE: varchar(40)
COLUMN_KEY:
EXTRA:
PRIVILEGES: select,insert,update,references
COLUMN_COMMENT:
*************************** 2. row ***************************
TABLE_CATALOG: def
TABLE_SCHEMA: danish_names
TABLE_NAME: european_names
COLUMN_NAME: greek_names
ORDINAL_POSITION: 2
COLUMN_DEFAULT: NULL
IS_NULLABLE: YES
DATA_TYPE: varchar
CHARACTER_MAXIMUM_LENGTH: 40
CHARACTER_OCTET_LENGTH: 40
NUMERIC_PRECISION: NULL
NUMERIC_SCALE: NULL
DATETIME_PRECISION: NULL
CHARACTER_SET_NAME: greek
COLLATION_NAME: greek_general_ci
COLUMN_TYPE: varchar(40)
COLUMN_KEY:
EXTRA:
PRIVILEGES: select,insert,update,references
COLUMN_COMMENT:
文件名
從MariaDB 5.1開始,系統變數character_set_filesystem可用來控制對給定字元串的文件名解析。它會影響的下麵語句和函數:
- SELECT INTO DUMPFILE
- SELECT INTO OUTFILE
- LOAD DATA INFILE
- LOAD XML
- LOAD_FILE()
字面符號(譯者註:可理解為常量、普通字元串或文本字元)
預設情況下,字元集和排序規則通過系統變數character_set_connection和collation_connection來決定使用的字面符號。但是可以顯式地指定它們:
[_charset_name]'string' [COLLATE collation_name]
對於沒有字元集introducer的字元集來說,它的字元串符號由系統變數character_set_connection決定。
該查詢:
SELECT CHARSET('a'), @@character_set_connection;
總是會為兩列返回相同的字元集名稱。
character_set_client和character_set_connection一般會被設置為相同的值(例如在三次握手期間,或使用SET NAMES進行了設置)。但允許設置為不同值。
示例
設置@@character_set_client和@@character_set_connection為不同的值時可能很有用處:
示例 1:
假設我們在utf8的資料庫中創建下麵的表:
CREATE TABLE t1 (a VARCHAR(10)) CHARACTER SET utf8 COLLATE utf8_general_ci;
INSERT INTO t1 VALUES ('oe'),('ö');
現在使用"mysql.exe"連接,它會使用DOS的字元集(西歐的機器上是cp850),如果想要根據德國電話簿規則獲取等於"ö"的所有記錄。
使用下麵的語句:
SET @@character_set_client=cp850, @@character_set_connection=utf8;
SELECT a FROM t1 WHERE a='ö' COLLATE utf8_german2_ci;
它將返回:
+------+
| a |
+------+
| oe |
| ö |
+------+
工作方式如下:
- 客戶端使用cp850發送查詢語句。
- 服務端解析查詢語句時,將把'ö'從@@character_set_client (cp850)轉換為@@character_set_connection (utf8)的文本字元。
- 服務端對該文本字元應用排序規則"utf8_germal2_ci"。
- 服務端使用utf8_german2_ci進行字元比較。
註意,如果重寫為如下腳本:
SET NAMES cp850;
SELECT a FROM t1 WHERE a='ö' COLLATE utf8_german2_ci;
將報錯:
ERROR 1253 (42000): COLLATION 'utf8_german2_ci' is not valid for CHARACTER SET 'cp850'
因為:
- 在第2步中,將不會轉換為utf8的文本字元,而是轉換為cp850的文本字元。
- 在第3步中,服務端無法對cp850的字元串應用排序規則utf8_german2_ci。
示例 2:
繼續假設我們的資料庫為utf8,並使用西歐機器上的"mysql.exe"進行連接。
我們這樣做:
SET @@character_set_client=cp850, @@character_set_connection=utf8;
CREATE TABLE t2 AS SELECT 'ö';
這將會創建一張包含VARCHAR(1) CHARACTER SET utf8欄位類型的表。
註意,如果查詢重寫為:
SET NAMES cp850;
CREATE TABLE t2 AS SELECT 'ö';
創建的表中的欄位將為VARCHAR(1) CHARACTER SET cp850類型,這可能不是我們所期望的。
N
同樣, 可以使用首碼N或n來轉換文本字元為國際字元集(MariaDB中為utf8)。
例如:
SELECT _latin2 'Müller';
+-----------+
| MĂźller |
+-----------+
| MĂźller |
+-----------+
SELECT CHARSET(N'a string');
+----------------------+
| CHARSET(N'a string') |
+----------------------+
| utf8 |
+----------------------+
SELECT 'Mueller' = 'Müller' COLLATE 'latin1_german2_ci';
+---------------------------------------------------+
| 'Mueller' = 'Müller' COLLATE 'latin1_german2_ci' |
+---------------------------------------------------+
| 1 |
+---------------------------------------------------+
存儲過程和視圖
當創建存儲過程或視圖時,其內出現的文本字元預設使用系統變數character_set_connection和collation_connection指定的字元集和排序規則。可以使用SHOW CREATE語句獲取所使用的值。要改變已存在存儲過程、視圖中的文本字元的字元集,需要刪除存儲程式然後重建。
對於存儲過程的參數和返回值,可以通過CHARACTER SET和COLLATE子句來指定其使用的字元集和排序規則。在MariaDB 5.5之前不支持指定排序規則。
下麵的示例中展示了創建存儲程式時所使用的字元集和排序規則。
SET @@local.character_set_connection='latin1';
DELIMITER ||
CREATE PROCEDURE `test`.`x`()
BEGIN
SELECT CHARSET('x');
END;
||
Query OK, 0 rows affected (0.00 sec)
DELIMITER ;
SET @@local.character_set_connection='utf8';
CALL `test`.`x`();
+--------------+
| CHARSET('x') |
+--------------+
| latin1 |
+--------------+
下麵的示例中展示瞭如何指定函數的參數和返回值的字元集和排序規則:
CREATE FUNCTION `test`.`y`(`str` TEXT CHARACTER SET utf8 COLLATE utf8_bin)
RETURNS TEXT CHARACTER SET latin1 COLLATE latin1_bin
BEGIN
SET @param_coll = COLLATION(`str`);
RETURN `str`;
END;
-- 返回值的排序規則:
SELECT COLLATION(`test`.`y`('Hello, planet!'));
+-----------------------------------------+
| COLLATION(`test`.`y`('Hello, planet!')) |
+-----------------------------------------+
| latin1_bin |
+-----------------------------------------+
-- 參數的排序規則:
SELECT @param_coll;
+-------------+
| @param_coll |
+-------------+
| utf8_bin |
+-------------+
示例:更改預設的字元集為UTF-8
要改變預設的字元集latin1為UTF-8,需要在配置文件my.cnf中進行如下設置:
[client]
...
default-character-set=utf8
...
[mysql]
...
default-character-set=utf8
...
[mysqld]
...
collation-server = utf8_unicode_ci
init-connect='SET NAMES utf8'
character-set-server = utf8
...
註意,選項default-character-set是一個客戶端選項,而非服務端選項。