本章主要介紹全球化,包含國際化和本地化,的一些問題:
· MySQL在語句中支持的字符集
· 如何為服務配置不同的字符集
· 選擇錯誤信息的語言
· 如何設置服務的時區和每個連接的時區
· 選擇本土化的日期和月份名
10.全球化... 1
10.1 字符集的支持... 2
10.1.1 字符集和排序規則... 2
10.1.2 mysql中的字符集和排序規則... 3
10.1.3 制定字符集和排序規則... 3
10.1.3.1 服務字符集和排序規則... 3
10.1.3.2 數據庫級字符集和排序規則... 3
10.1.3.3 表的字符集和排序規則... 4
10.1.3.4 列的字符集和排序規則... 4
10.1.3.5 字符串常量的字符集和排序規則... 5
10.1.3.6 National Character Set6
10.1.3.7 字符集和排序規則設置的例子... 6
10.1.3.8 和其他數據的兼容... 6
10.1.4 連接的字符集和排序規則... 7
10.1.5 為應用程序配置字符集和排序規則... 8
10.1.5.1 為每個數據指定字符集和排序規則... 8
10.1.5.2 在服務啟動是配置字符集... 8
10.1.5.3 在Mysql配置的時候設置字符集和排序規則... 8
10.1.6 錯誤信息的字符集... 9
10.1.7 排序規則... 9
10.1.7.1 排序規則名... 9
10.1.7.2 在語句中使用排序規則... 9
10.1.7.3 COLLATE子句... 10
10.1.7.4 排序規則必須要一個正確的字符集... 10
10.1.7.5 表達式中的排序規則... 10
10.1.7.6 _bin和binary. 11
10.1.7.7 BINARY操作... 13
10.1.7.8 Collation的影響例子... 13
10.1.7.9 排序規則和INFORMATION_SCHEMA查找... 13
10.1.8 字符目錄(String Repertoire)15
10.1.9 受字符集影響的操作... 16
10.1.9.1 結果字符串... 16
10.1.9.2 CONVERT()和CAST()16
10.1.9.3 SHOW語句和INFORMATION_SCHEMA.. 16
10.1.10 Unicode支持... 16
10.1.10.1 ucs2字符集... 17
10.1.10.2 utf16字符集... 17
10.1.10.3 utf16le字符集... 17
10.1.10.4 utf32字符集... 17
10.1.10.5 utf8字符集... 17
10.1.10.6 utf8mb3字符集... 18
10.1.10.7 utf8mb4字符集... 18
10.1.11 更新unicode的支持... 18
10.1.12 元數據為utf8. 19
10.1.13 列字符集轉化... 19
10.1.14 MySQL支持的字符集和排序規則... 20
10.2 設置錯誤信息語言... 20
10.3 增加一個字符集... 20
10.4 為字符集增加一個排序規則... 20
10.5 配置字符集... 20
10.6 MySQL時區的支持... 20
10.6.1 跟上時區修改... 21
10.6.2 時區閏秒支持(Time Zone Leap Seconad Support)22
10.7 MySQL Server本地化支持... 23
Mysql可以讓你使用不同的字符集來保存數據,可以再多個排序規則下比較數據。可以再服務,數據庫,表和列級別設置字符集。本章回答以下幾個問題:
· 使用什麼字符集和排序規則
· 多個級別的系統默認字符集的分配
· 設置字符集和排序規則的設置語法
· 會收到影響的函數和操作
· Unicode 的支持
· 可用的字符集和排序規則
字符集不單單影響數據存儲,也會影響client和server之間的交互。可以使用set names來設置client和server之間交互使用的字符集。
字符集是一堆符號和編碼,排序規則是字符集的比較規則。比如比較“A”和“B”最簡單的方法是比較編碼,這種排序規則也是最簡單的排序規則,成為binary排序規則。
對於a=A,b=B我們成為大小寫不敏感的排序規則。每個字符集有很多個排序規則。
mysql可以做到以下一些:
1.可以以多個字符集保存字符串
2.比較字符串可以使用不同的排序規則
3.在同一個服務中可以混合多個字符集和排序規則
4.字符集和排序規則有很多級別(server,db,tb.column)
Mysql可以支持多個字符集,可以使用SHOW CHARACTER SET來顯示。一個字符集有多個排序規則,至少一個,可以使用SHOW COLLATION,查看。
排序規則有以下一些特性:
· 2個不同的字符集不可能擁有同一個排序規則
· 每個字符集都有一個默認排序規則
· 排序規則命名,一般是字符集名,語言名,後綴。後綴有_ci(大小寫不明感),_cs(大小寫敏感),_bin(binary)
避免使用錯的排序規則,保證制定的排序規則給出的順序是你要的。
在4個級別上會設置默認的字符集和排序規則,CHARACTER SET可以用來設置指定字符集。CHARSET是CHARACTER SET的另外一種寫法。
字符集不單單影響數據存儲,也會影響客戶端和服務器之間的交互。
服務級別的字符集和排序規則可以在命令行和配置文件中設置。使用—character-set-server設置字符集,--collation-server設置排序規則。
shell> mysqld
shell> mysqld --character-set-server=latin1
shell> mysqld --character-set-server=latin1 \
--collation-server=latin1_swedish_ci
如果要修改默認的服務級的字符集和排序規則,可以通過重編譯源代碼進行。
shell> cmake . -DDEFAULT_CHARSET=latin1
或
shell> cmake . -DDEFAULT_CHARSET=latin1 \
-DDEFAULT_COLLATION=latin1_german1_ci
Mysqld和CMake都會驗證字符集和排序規則是否可用,如果不可用每個程序都會顯示錯誤信息和中斷。
當create database沒有指定,會使用服務的字符集和排序規則。Character_set_server和collation_server指定了服務的字符集和排序規則。這些變量可以再運行時被修改。
數據庫級的排序規則可以使用create database和alterdatabase來指定。
CREATE DATABASE db_name
[[DEFAULT] CHARACTER SET charset_name]
[[DEFAULT] COLLATE collation_name]
ALTER DATABASE db_name
[[DEFAULT] CHARACTER SET charset_name]
[[DEFAULT] COLLATE collation_name]
CHARACTER_SET,COLLATE子句可以指定不同於服務的字符集和排序規則。
CREATE DATABASE db_name CHARACTER SET latin1 COLLATE latin1_swedish_ci;
Mysql以以下方式來獲取字符集和排序規則:
· 如果指定了CHARACTER SET X和COLLATE Y,那麼會使用字符集x,排序規則y
· 如果指定了字符集x沒有指定排序規則,那麼使用默認的排序規則。
· 如果指定了排序規則沒有指定字符集,那麼使用和排序規則相關的字符集。
· 否則使用服務的字符集和排序規則。
和創建數據庫一樣,創建表的時候沒有指定就使用數據庫級的字符集和排序規則。Character_set_database和collation_database系統變量,當有數據庫時,為數據庫的字符集和排序規則,如果沒有數據庫時是server的字符集和排序規則。
表的排序規則可以通過create table和alter table來修改。
CREATE TABLE tbl_name (column_list)
[[DEFAULT] CHARACTER SET charset_name]
[COLLATE collation_name]]
ALTER TABLE tbl_name
[[DEFAULT] CHARACTER SET charset_name]
[COLLATE collation_name]
表選擇字符集和排序規則和數據庫一致。
如果創建表時,表沒有指定列的字符集和排序規則,那麼就用表的字符集和排序規則。
列的字符集和排序規則通過create table和alter table來指定。
col_name {CHAR | VARCHAR | TEXT} (col_length)
[CHARACTER SET charset_name]
[COLLATE collation_name]
col_name {ENUM | SET} (val_list)
[CHARACTER SET charset_name]
[COLLATE collation_name]
如:
CREATE TABLE t1
(
col1 VARCHAR(5)
CHARACTER SET latin1
COLLATE latin1_german1_ci
);
ALTER TABLE t1 MODIFY
col1 VARCHAR(5)
CHARACTER SET latin1
COLLATE latin1_swedish_ci;
Mysql為列選擇字符集和排序規則的方法和表一樣。
如果alter table從一個字符集轉為另外一個字符集的時候,如果字符集不兼容那麼就有可能丟失數據。
每個字符串都有一個字符集和排序規則。指定字符串常量字符集的方法:
[_charset_name]'string' [COLLATE collation_name]
例如:
SELECT 'string';
SELECT _latin1'string';
SELECT _latin1'string' COLLATE latin1_danish_ci;
如果什麼都沒有指定,那麼使用連接的字符集和排序規則,character_set_connection和collation_connection決定。
Mysql選擇字符集和排序規則的方式如下:
· 如果指定了字符集x和排序規則y,那麼就是用x,y
· 如果指定了字符集沒有指定排序規則,那麼使用x和x的默認排序規則
· 否則使用變量character_set_connection和collation_connection
前面指定的字符集並不影響轉移字符,轉移字符是受character_set_connection影響。
如
mysql> SET NAMES latin1;
Query OK, 0 rows affected (0.01 sec)
mysql> SELECT HEX('à\n'), HEX(_sjis'à\n');
+------------+-----------------+
| HEX('à\n') | HEX(_sjis'à\n') |
+------------+-----------------+
| E00A | E00A |
+------------+-----------------+
1 row in set (0.00 sec)
mysql> SET NAMES sjis;
Query OK, 0 rows affected (0.00 sec)
mysql> SELECT HEX('à\n'), HEX(_latin1'à\n');
+------------+-------------------+
| HEX('à\n') | HEX(_latin1'à\n') |
+------------+-------------------+
| E05C6E | E05C6E |
+------------+-------------------+
1 row in set (0.04 sec)
在字符集sjis中“\”並不認為是轉移“\”=5C,“n”=6E。
標准SQL定義NCHAR或者 NATIONAL CHAR來說明這個char列要使用預定於的字符集。Mysql 5.6使用utf8作為預定義的字符集。可以通過N’some text’來創建national 字符集內的字符串。
1.設置列和表的字符集和排序規則
CREATE TABLE t1
(
c1 CHAR(10) CHARACTER SET latin1 COLLATE latin1_german1_ci
) DEFAULT CHARACTER SET latin2 COLLATE latin2_bin;
2.列不帶排序規則
CREATE TABLE t1
(
c1 CHAR(10) CHARACTER SET latin1
) DEFAULT CHARACTER SET latin1 COLLATE latin1_danish_ci;
3.列不帶字符集和排序規則
CREATE TABLE t1
(
c1 CHAR(10)
) DEFAULT CHARACTER SET latin1 COLLATE latin1_danish_ci;
4.數據庫設置排序規則和字符集,表和列不設置
CREATE DATABASE d1
DEFAULT CHARACTER SET latin2 COLLATE latin2_czech_ci;
USE d1;
CREATE TABLE t1
(
c1 CHAR(10)
);
略
連接的字符集和排序規則主要說明一下一些問題:
· 當客戶端發送前語句的時候使用什麼字符集,character_set_client
· 語句在傳輸過程中是什麼字符集,character_set_connection,和排序規則collation_connection,然後會從character_set_client轉化為character_set_connection。
· 在傳輸錯誤或者結果到客戶端前字符集是什麼,character_set_results指定了返回前的字符集。
有2個語句會影響和連接相關的字符集變量
· SET NAMES ‘charset_name’[COLLATE ‘collation_name’]
SET NAMES相當於以下3個語句
SET character_set_client = charset_name;
SET character_set_results = charset_name;
SET character_set_connection = charset_name;
· 使用SET語句設置,如:
SET character_set_client = charset_name;
SET character_set_results = charset_name;
SET collation_connection = @@collation_database;
Mysql的一些客戶端程序如mysql,MySQLadmin,mysqlcheck,mysqlimport,mysqlshow決定默認字符集規則如下:
· 在沒有信息的情況下使用Latin1字符集
· 程序可以自動識別OS上使用的字符集,如LANG或者LC_ALL。或者windows上的codepage來判斷
· 程序也支持使用—default-character-set選項,顯示的設置字符集。
在程序連接服務的時候,使用程序要的字符集發送給服務,然後何止,character_set_client,character_set_results和character_set_connection系統變量。事實上可以使用set names來設置。
如果默認的和你想要的不一樣可以使用set names來設置或者加上參數—default-caracter-set,或者加在配置文件中。
[mysql]
default-character-set=koi8r
如果可以自動重連,可以使用charset命令:
mysql> charset utf8
Charset changed
Charset命令使用set names,然後修改mysql的默認字符集,然後重連。
假設列column1定義為char(5) CHARACTER SET latin2。如果沒有設置set names和set character set。那麼mysql會以column1的字符集和排序規則來發送數據,如果設置了set names latin1,那麼會把latin2轉化為latin1然後再發送。
如果要嘗試直接發送:
SET character_set_results = NULL;
應用程序存數據使用默認的字符集和排序規則。如果應用程序要不同的排序規則和字符集,可以通過幾個方式來配置:
· 為每個數據庫指定一個字符集
· 在服務啟動的時候指定一個字符集
· 在mysql編譯的時候配置字符集
如果所有的或者大多數的應用程序使用相同的字符集,可以再服務啟動的時候或者配置mysql的時候設置。
在create database中設置如:
CREATE DATABASE mydb
DEFAULT CHARACTER SET utf8
DEFAULT COLLATE utf8_general_ci;
應用程序在使用這個數據庫的時候,每次連接都要配置可以指定—default-character-set=utf8或者set names=‘utf8’。
如果修改了數據庫的字符集和排序規則,那麼所有的過程都要被重建。
在服務啟動的時候,使用命令行—character-set-server和—collation-server,或者設置配置文件:
[mysqld]
character-set-server=utf8
collation-server=utf8_general_ci
這些配置是服務級別的,所以在創建數據庫的時候會以這個為默認的字符集和排序規則。一旦設置了之後,每個連接可能都要設置一下排序規則,那麼可以再系統啟動的時候設置—init_connect=”SET NAMES ‘utf8’”,這樣每次連接的時候都會運行一下set names命令。
設置方法:
shell> cmake . -DDEFAULT_CHARSET=utf8 \
-DDEFAULT_COLLATION=utf8_general_ci
在mysql 5.6,服務使用utf8構建消息,並且通過character_set_results系統變量來返回。
服務構建錯誤消息的過程:
· 消息模板使用utf8
· 然後消息中的參數被替換
o 如表名,列名會被原樣復制
o 如果是字符串那麼會被轉化成utf8
o 如果是二進制串恢復0x20到0x7e之間的值,其他的會被加上前綴\x
o Duplicate entry 'A\xC3\x9F' for key 1
如果構建完就會發送給client,字符集會從utf8轉化為character_set_results系統變量。如果變量為null或者binary不會發送轉化。
如果字符在character_set_results上沒辦法體現,某些字符可能發生某些編碼。編碼使用unicode指針值:
· 如果字符在BMP(Basic Multilingual Plane)范圍內(0x0000-0xffff)寫成\nnnn
· 如果再范圍之外室友\+nnnnnn
客戶端可以控制character_set_results來控制接受的字符串的字符集。
排序規則名一般以_ci,_cs,_bin結尾
· With ORDER BY:
SELECT k
FROM t1
ORDER BY k COLLATE latin1_german2_ci;
· With AS:
SELECT k COLLATE latin1_german2_ci AS k1
FROM t1
ORDER BY k1;
· With GROUP BY:
SELECT k
FROM t1
GROUP BY k COLLATE latin1_german2_ci;
· With aggregate functions:
SELECT MAX(k COLLATE latin1_german2_ci)
FROM t1;
· With DISTINCT:
SELECT DISTINCT k COLLATE latin1_german2_ci
FROM t1;
· With WHERE:
SELECT *
FROM t1
WHERE _latin1 'Müller' COLLATE latin1_german2_ci = k;
SELECT *
FROM t1
WHERE k LIKE _latin1 'Müller' COLLATE latin1_german2_ci;
· With HAVING:
SELECT k
FROM t1
GROUP BY k
HAVING k = _latin1 'Müller' COLLATE latin1_german2_ci;
COLLATE比||優先級要高,所以下面語句是等價的:
x || y COLLATE z
x || (y COLLATE z)
一個字符集有多個排序規則,但是一個排序規則只能對應到一個字符集,因此如果出現以下情況那麼就會報錯:
mysql> SELECT _latin1 'x' COLLATE latin2_bin;
ERROR 1253 (42000): COLLATION 'latin2_bin' is not valid
for CHARACTER SET 'latin1'
排序規則的主要用處是用來比較,如:
SELECT x FROM T ORDER BY x;
SELECT x FROM T WHERE x = x;
SELECT DISTINCT x FROM T;
如果是2個不同的操作數,可能排序規則會歧義如:
SELECT x FROM T WHERE x = 'Y';
出現這種情況標准的sql使用可壓縮性規則來確定使用什麼字符集。可壓縮性值有以下決定:
· 一個現實的COLLATE子句的可壓縮性值為0
· 並列的2個字符串有2個不同的排序規則,那麼可壓縮性為1
· 列或者存儲的參數的排序規則可壓縮性為2
· 系統常量,或者USER(),VERSION()的可壓縮性為3
· 字符串常量的可壓縮性值為4
· Null的可壓縮性值為5
Mysql使用可壓縮性值來解決這個問題:
· 使用可壓縮值最低的
· 如果吹按可壓縮值相同
o 如果2邊都是unicode或者都不是那麼就報錯
o 如果一邊是unicode,一邊不是那麼傳為非unicode
o 如果操作字符集相同,但是排序規則不同,比如_bin混合了_ci,_cs那麼使用_bin。
可壓縮性值,可以通過coercibility查看
對於使用concat隱式轉化的字符集和排序規則有連接的字符集和排序規則決定。
串有2中,一種是字符串(Nonbinary string),一種是二進制串(binary string)。
Nonbinary string以數據類型char,varchar,text保存,有字符集和排序規則。
Binary string以binary,varbinary,blob類型保存,無字符集和排序規則。
在很多方面_bin排序規則和binary排序規則不同。
Binary string是字節流。比較是根據字節的值來比較。Nonbinary string是字符流,所以比較是以一個字符來進行比較。Nonbinary strings的排序規則定義了字符的順序和比較。對於_bin排序規則就是以字符的二進制的值進行排序。
Nonbinary strings可以轉化為其他字符集的字符串,就算是_bin排序規則的。但是對於binary strings就不會發生轉化。
Nonbinary strings可以大小寫轉化:
mysql> SET NAMES latin1 COLLATE latin1_bin;
Query OK, 0 rows affected (0.02 sec)
mysql> SELECT LOWER('aA'), UPPER('zZ');
+-------------+-------------+
| LOWER('aA') | UPPER('zZ') |
+-------------+-------------+
| aa | ZZ |
+-------------+-------------+
1 row in set (0.13 sec)
在binary strings中是不能轉化的:
mysql> SET NAMES binary;
Query OK, 0 rows affected (0.00 sec)
mysql> SELECT LOWER('aA'), LOWER(CONVERT('aA' USING latin1));
+-------------+-----------------------------------+
| LOWER('aA') | LOWER(CONVERT('aA' USING latin1)) |
+-------------+-----------------------------------+
| aA | aa |
+-------------+-----------------------------------+
1 row in set (0.00 sec)
Nonbinary strings所有的排序規則有PADSPACE行為。
mysql> SET NAMES utf8 COLLATE utf8_bin;
Query OK, 0 rows affected (0.00 sec)
mysql> SELECT 'a ' = 'a';
+------------+
| 'a ' = 'a' |
+------------+
| 1 |
+------------+
1 row in set (0.00 sec)
但是binary string不行
mysql> SET NAMES binary;
Query OK, 0 rows affected (0.00 sec)
mysql> SELECT 'a ' = 'a';
+------------+
| 'a ' = 'a' |
+------------+
| 0 |
+------------+
1 row in set (0.00 sec)
CHAR(N)保存nonbinary strings數據,當插入長度不足N會以空格插入。
binary(N)保存binary string數據,會以0x00填充。
mysql> CREATE TABLE t1 (
-> a CHAR(10) CHARACTER SET utf8 COLLATE utf8_bin,
-> b BINARY(10)
-> );
Query OK, 0 rows affected (0.09 sec)
mysql> INSERT INTO t1 VALUES ('a','a');
Query OK, 1 row affected (0.01 sec)
mysql> SELECT HEX(a), HEX(b) FROM t1;
+--------+----------------------+
| HEX(a) | HEX(b) |
+--------+----------------------+
| 61 | 61000000000000000000 |
+--------+----------------------+
1 row in set (0.04 sec)
Binary操作是把它之後的字符串變為binary string。BINARY str是cast(str as BINARY)的縮寫。
略
INFORMATION_SCHEMA表的字符串列的排序規則是uft8_genernal_ci,大小寫不敏感。但是文件系統的是否大小寫敏感也會影響INFORMATION_SCHEMA的字符串列。如linux系統上大小寫是敏感的。
在linux 下:
mysql> SELECT SCHEMA_NAME FROM INFORMATION_SCHEMA.SCHEMATA
-> WHERE SCHEMA_NAME = 'test';
+-------------+
| SCHEMA_NAME |
+-------------+
| test |
+-------------+
1 row in set (0.01 sec)
mysql> SELECT SCHEMA_NAME FROM INFORMATION_SCHEMA.SCHEMATA
-> WHERE SCHEMA_NAME = 'TEST';
Empty set (0.00 sec)
在windows下:
mysql> SELECT SCHEMA_NAME FROM INFORMATION_SCHEMA.SCHEMATA
-> WHERE SCHEMA_NAME = 'test';
+-------------+
| SCHEMA_NAME |
+-------------+
| test |
+-------------+
1 row in set (0.00 sec)
mysql> SELECT SCHEMA_NAME FROM INFORMATION_SCHEMA.SCHEMATA
-> WHERE SCHEMA_NAME = 'TEST';
+-------------+
| SCHEMA_NAME |
+-------------+
| TEST |
+-------------+
1 row in set (0.00 sec)
如果列的排序規則和想到的不同,可以使用COLLATE語句顯示指定一個排序規則:
mysql> SELECT SCHEMA_NAME FROM INFORMATION_SCHEMA.SCHEMATA
-> WHERE SCHEMA_NAME COLLATE utf8_general_ci = 'test';
+-------------+
| SCHEMA_NAME |
+-------------+
| test |
+-------------+
1 row in set (0.00 sec)
mysql> SELECT SCHEMA_NAME FROM INFORMATION_SCHEMA.SCHEMATA
-> WHERE SCHEMA_NAME COLLATE utf8_general_ci = 'TEST';
| SCHEMA_NAME |
+-------------+
| test |
+-------------+
1 row in set (0.00 sec)
當然也可以使用UPPER(),LOWER()。
字符集目錄是字符集合。
字符串表達式有2種目錄屬性:
ASCII:只能包含unicode范圍中U+0000到U+007U。
UNICODE:包含unicode范圍從U+0000到U+FFFF。
ASCII是UNICODE的子集。
使用以下例子來說明目錄:
· 字符串的內容限制了目錄
SET NAMES utf8; SELECT 'abc';
SELECT _utf8'def';
SELECT N'MySQL';
盡管是使用了utf8字符集,但是只使用了ASCII范圍的所以目錄是ASCII。不是unicode。
· 有ascii字符集的列有ASCII目錄。2個列concat的時候只能是子集連接超集,如:
CREATE TABLE t1 (
c1 CHAR(1) CHARACTER SET latin1,
c2 CHAR(1) CHARACTER SET ascii
);
INSERT INTO t1 VALUES ('a','b');
SELECT CONCAT(c1,c2) FROM t1;
ERROR 1267 (HY000): Illegal mix of collations (latin1_swedish_ci,IMPLICIT)
and (ascii_general_ci,IMPLICIT) for operation 'concat'
如果是子集連接超集。
+---------------+
| CONCAT(c1,c2) |
+---------------+
| ab |
+---------------+
· 有一個字符串參數的函數,會集成參數的目錄,如UPPER(_utf8’abc’)是ASCII目錄。
· 如果函數返回字符串,但是沒有字符串參數,那麼字符集使用chararter_set_connection作為結果,如果字符集是ascii那麼目錄使用ascii,否則使用unicode。
· 當函數有2個或者2個以上字符參數時,使用最寬的目錄,如unicode比ascii寬,
CONCAT(_ucs2 0x0041, _ucs2 0x0042)
CONCAT(_ucs2 0x0041, _ucs2 0x00C2)
第一個函數都沒超過ascii range,那麼就是ascii,第二個超過了ascii,那麼就是unicode。
· 函數的返回字符串的目錄由參數的目錄決定
Mysql有很多操作和函數返回字符串。那麼本節介紹結果字符串的排序規則和字符集。
對於簡單的函數,輸入字符串的,那麼輸出的字符串和輸入的字符串的排序規則和字符集一樣。
如果輸入或者輸出的字符串是binary串,那麼是沒有字符集和排序規則的,charset()和collation()都是返回binary。
如果有對個數據字符串,一個輸出,那麼有以下規則決定輸出的排序規則:
· 如果現實的指定了collate x那麼使用x
· 如果指定了collate x,collate y,報錯
· 如果所有的排序規則是x,那麼使用x
· 否則結果沒有排序規則
Convert提供了字符串在不同字符集上轉化的功能
CONVERT(expr USING transcoding_name)
如:
SELECT CONVERT(_latin1'Müller' USING utf8);
INSERT INTO utf8table (utf8column)
SELECT CONVERT(latin1field USING utf8) FROM latin1table;
也可以使用cast,
CAST(character_string AS character_data_type CHARACTER SET charset_name)
如:
SELECT CAST(_latin1'test' AS CHAR CHARACTER SET utf8);
Convert和cast上不能使用字符集,可以再函數外面使用:
SELECT CAST(_latin1'test' AS CHAR CHARACTER SET utf8) COLLATE utf8_bin;
show命令的結果會提供一些字符集合排序規則信息,INFORMATION_SCHEMA和show命令類似。
起初,mysql 4.1中就支持2中保存unicode的方式:
· Ucs2:每個字節使用2個字節來編碼。
· Utf8:每個字節1-3個字節。
這2個字符集支持來自unicode 3.0 BMP的字符。
如果超出BMP的字符會被替換為‘?’
在mysql 5.6,為了要支持新的unicode的字符,所以增加了新的字符集。
Mysql 5.6支持的字符集:
Ucs2:有2個字節來編碼
Utf16:和ucs2類似,但是多了新增的字符
Utf16le:utf16是大端的,utf16le是小端的
Utf32:每個字符3個字節
Utf8:每個字符1-3個字節
Utf8mb4:1-4個字節編碼
Ucs2,utf8支持BMP字符,utf8mb4,utf16,utf16le和utf32支持BMP字符和額外字符。
在ucs2字符集中,每個字符占2個字節。
Utf16是ucs2加上一些新增的字符,有以下 特性:
· 對於BMP字符,utf16個ucs2編發都是一樣的
· 對於增益的字符,如果大於0xffff,加上0xd800,放到前16bit,然後去之後的10bit加上0xdc00放到後16bit。
和utf16一樣,只是是小端的。
Utf32的字符長度是固定的,4個字節。在使用的時候要注意,定義的長度必須是4字節的倍數。
Uft8是一種保存unicode的替代方案。
Utf8把字符以不同的字節長度進行編碼:
· 基本的Latin字母,數字和標點符號使用一個字節。
· 大多數歐洲,中東字符使用2個字節。
· 韓文,中文,日文在3個或者4個字節中。
Utf8在mysql5.6還是之前的版本都有2個特點:
· 不支持新增字符。
· 最多每個字符3個字節。
Uft8和ucs2有相同的目錄
在未來utf8會變成4字節的utf8,之前的3字節的utf8要被稱為utf8mb8。為了避免將來復制之間的版本不同導致字符集問題,可以讓用戶指定utf8mb3字符集和排序規則。如:
CREATE TABLE t (s1 CHAR(1) CHARACTER SET utf8mb3;
SELECT * FROM t WHERE s1 COLLATE utf8mb3_general_ci = 'x';
DECLARE x VARCHAR(5) CHARACTER SET utf8mb3 COLLATE utf8mb3_danish_ci;
SELECT CAST('a' AS CHAR CHARACTER SET utf8) COLLATE utf8_czech_ci;
這時,mysql會吧utf8mb3轉化為utf8.目前utf8mb3只能用在CHARACTER SET子句上。
Utf8字符集一個字符最多3個字節,並且只包含BMP字符。Utf8mb4是最多使用每個字符4個字節:
· 對於BMP,utf8和utf8mb4都是一樣的存儲特性,同樣的code值,同樣的編碼,同樣的長度。
· 對於新增的字符,utf8buneng baocun ,utf8mb4需要4個字節來保存。
Utf8mb4是utf8的超集。
對於utf8mb4個utf8比,在相同的長度下utf8能夠存更多的字符。可以使用alter table把utf8轉成utf8mb4:
CREATE TABLE t1 (
col1 CHAR(10) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL,
col2 CHAR(10) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL
) CHARACTER SET utf8;
ALTER TABLE t1
DEFAULT CHARACTER SET utf8mb4,
MODIFY col1 CHAR(10)
CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
MODIFY col2 CHAR(10)
CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;
對於BMP字符來說,utf8和utf8mb4沒有什麼差別,但是utf8不支持新增字符。
對於所有的char,varchar,text需要注意:
· 檢查所有的utf8定義的列,不會超過引擎的最大值
· 檢查utf8的索引,不會超過引擎的最大值。
如果上面條件不滿足,那麼只能使用utf8.還有一些例子修改字符集可能要修改表結構:
· Tinytext類型,只有255個字節,如果使用3個字節一個字符最多可以存85個,如果4字節那麼最多63個。如果要使用utf8mb4又要超過63個字符,那麼需要修改表結構。
· Innodb索引,如果使用COMPACT或REDUNDANT行格式,最長767個字節。對於utf8和utf8mb4來說,最多可以保存255和191個字符。也就是說,如果utf8長度超過191個字符,要轉化為utf8mb4那麼是不夠的。
還有一些utf8和utf8mb4的比較:
· 4字節的utf8比3字節的utf8性能差
· Set names ‘utf8mb4’連接字符集會是4字節字符集,如果沒有4個字節字符發送就沒有問題。否則應用程序視圖以最大3個字節獲取信息可能會出問題。
· 應用不能發utf16,utf16le,utf32發送數據到老的服務
· 對於復制,如果master支持新增的字符集,那麼slave必須也支持。
如果要從新系統換成老系統:
· Ucs2和utf8是沒問題的
· 老系統不支持utf8mb4,utf16,utf16le,utf32
· 對於使用了utf8mb4的對象定義,可以先dump,然後把utf8mb4轉為utf8。
元數據需要滿足以下特點:
· 所有的元數據要使用同一個字符集。
· 元數據必須包含所有語言的字符。
為了滿足這個條件,mysql使用utf8字符集來存元數據。比如函數USER(),CURRENT_USER(),SESSION_USER(),SYSTEM_USER(),DATEBASE()和VERSION(),默認都是使用utf8。
使用character_set_system系統變量來控制元數據的字符集。
元數據是以character_set_system保存的,並不意味著DESCRIBE函數返回的字符集也是默認character_set_system字符集。如select column1 from t,從服務器返回給client,column1的字符集是由character_set_results決定的,默認為latin1。如果想要把元數據的結果以其他字符集傳輸,可以使用set name 來設置。如果character_set_results為null,那麼就不會發出轉化,如果是元數據,那麼會以character_Set_system字符集傳輸。
如果在表達式中使用user()那麼mysql會自動進行傳化。
SELECT * FROM t1 WHERE USER() = latin1_column;
INSERT INTO t1 (latin1_column) SELECT USER();
使用alter table把binary string或者nonbinary string 指定特定字符集。
· 如果列是bianry數據類型(BINARY,VARBINARY,BLOB)那麼所有的值只能是一個字符集。
· 如果是nonbinary數據類型(char,varchar,text)包含的值,只能變編碼為列自定的字符集。
假設表t是有一個col1定義為varbinary,使用一個字符集編碼,並且為greek,那麼可以通過以下語句去轉化:
ALTER TABLE t MODIFY col1 VARCHAR(50) CHARACTER SET greek;
如果類型是binary(50),那麼可以轉化為char(50)但是,可能會出現0x00在末尾可能無法描述,需要使用trim();
UPDATE t SET col1 = TRIM(TRAILING 0x00 FROM col1);
如果表t有col1 char(50) character set latin1,要轉化為utf8,可以直接:
ALTER TABLE t MODIFY col1 CHAR(50) CHARACTER SET utf8;
略
默認mysql的錯誤信息是英語,但是可以指定其他語言。
在mysql 5.6中錯誤信息在以下2個目錄下去查找:
· 會從lc_messages_dir和lc_messages 2個系統變量上去查找,使用如下:
shell> mysqld --lc_messages_dir=/usr/share/mysql --lc_messages=fr_FR
· 如果找不到,那麼會放棄lc_messages,直接通過lc_messages_dir來查找。
lc_messages_dir是全局只讀變量,lc_messages是全局和會話變量,可以運行時修改。默認語言文件在share/mysql/LANGUAGE目錄下。
略
略
略
mysql時區有好幾個維護時區的設置:
· 系統級別的時區,當服務啟動的時候,把系統使用的時區賦值給system_time_zone系統變量
· 服務當前時區,全局time_zone,表明當前所在的時區,初始值是’SYSTEM’表示和服務時區一樣。全局服務時間可以在啟動時設置,可以使用--default-time-zone。
· 每個連接的時區,當連接的時候會話變量time_zone和全局time_zone一樣,但是可以自己修改。
當前的時區,不會對UTC_TIMESTAMP()和date,time,datetime列的值進行影響。當前的時區可以通過以下方式獲取:
mysql> SELECT @@global.time_zone, @@session.time_zone;
時區的值可以是以下幾種:
· ‘SYSTEM’表示和服務的時區一樣
· ‘+10:00’,’-6:00’直接設置時區
· 使用命名的時區,如 ‘Europe/Helsinki’
mysql安裝的時候會生成時區表在mysql數據庫內,但是不會被load需要手動load。
如果系統有自己的時區信息,那麼可以使用mysql_tzinfo_to_sql程序來填充時區表,如linux,時區信息在/usr/shar/zoneinfo目錄下。如果沒有時區庫,那麼可以自己去下載。
mysql_tzinfo_to_sql用來把時區信息導入到時區表中:
shell> mysql_tzinfo_to_sql /usr/share/zoneinfo | mysql -u root mysql
當時區被修改的時候,應用程序還是使用老的時區,為了跟上,確定系統使用的時區信息是很有必要的。對於mysql有2個方式可以用於跟上時區:
· 如果時區設置為‘system’那麼操作系統的時區會影響mysql服務的事務。
· 如果實在/ect/localtime時區文件中替換,你就應該重啟mysqld才能更新修改後的時區。
如果使用命名時區,那麼要保證時區表中的數據時最新的。若系統有自己的時區信息,那麼系統的時區信息被更新的時候,要保證mysql內的時區信息也要被更新。mysqld會cache時區信息因此更新後需要重啟服務。如果你要使用命名時區但是不確定有沒有,那麼先查看時區表。
mysql> SELECT COUNT(*) FROM mysql.time_zone_name;
+----------+
| COUNT(*) |
+----------+
| 0 |
+----------+
若不為空那麼說明可以使用命名時區。
檢查是否有夏令時規則:
SELECT CONVERT_TZ('2007-03-11 2:00:00','US/Eastern','US/Central');
SELECT CONVERT_TZ('2007-03-11 3:00:00','US/Eastern','US/Central');
更新前:
mysql> SELECT CONVERT_TZ('2007-03-11 2:00:00','US/Eastern','US/Central');
+------------------------------------------------------------+
| CONVERT_TZ('2007-03-11 2:00:00','US/Eastern','US/Central') |
+------------------------------------------------------------+
| 2007-03-11 01:00:00 |
+------------------------------------------------------------+
mysql> SELECT CONVERT_TZ('2007-03-11 3:00:00','US/Eastern','US/Central');
+------------------------------------------------------------+
| CONVERT_TZ('2007-03-11 3:00:00','US/Eastern','US/Central') |
+------------------------------------------------------------+
| 2007-03-11 02:00:00 |
+------------------------------------------------------------+
更新後:
mysql> SELECT CONVERT_TZ('2007-03-11 2:00:00','US/Eastern','US/Central');
+------------------------------------------------------------+
| CONVERT_TZ('2007-03-11 2:00:00','US/Eastern','US/Central') |
+------------------------------------------------------------+
| 2007-03-11 01:00:00 |
+------------------------------------------------------------+
mysql> SELECT CONVERT_TZ('2007-03-11 3:00:00','US/Eastern','US/Central');
+------------------------------------------------------------+
| CONVERT_TZ('2007-03-11 3:00:00','US/Eastern','US/Central') |
+------------------------------------------------------------+
| 2007-03-11 01:00:00 |
+------------------------------------------------------------+
如果出現閏秒(23:59:60)情況會使用59:59。
mysql> CREATE TABLE t1 (
-> a INT,
-> ts TIMESTAMP DEFAULT NOW(),
-> PRIMARY KEY (ts)
-> );
Query OK, 0 rows affected (0.01 sec)
mysql> -- change to UTC
mysql> SET time_zone = '+00:00';
Query OK, 0 rows affected (0.00 sec)
mysql> -- Simulate NOW() = '2008-12-31 23:59:59'
mysql> SET timestamp = 1230767999;
Query OK, 0 rows affected (0.00 sec)
mysql> INSERT INTO t1 (a) VALUES (1);
Query OK, 1 row affected (0.00 sec)
mysql> -- Simulate NOW() = '2008-12-31 23:59:60'
mysql> SET timestamp = 1230768000;
Query OK, 0 rows affected (0.00 sec)
mysql> INSERT INTO t1 (a) VALUES (2);
Query OK, 1 row affected (0.00 sec)
mysql> -- values differ internally but display the same
mysql> SELECT a, ts, UNIX_TIMESTAMP(ts) FROM t1;
+------+---------------------+--------------------+
| a | ts | UNIX_TIMESTAMP(ts) |
+------+---------------------+--------------------+
| 1 | 2008-12-31 23:59:59 | 1230767999 |
| 2 | 2008-12-31 23:59:59 | 1230768000 |
+------+---------------------+--------------------+
2 rows in set (0.00 sec)
mysql> -- only the non-leap value matches
mysql> SELECT * FROM t1 WHERE ts = '2008-12-31 23:59:59';
+------+---------------------+
| a | ts
+------+---------------------+
| 1 | 2008-12-31 23:59:59 |
+------+---------------------+
1 row in set (0.00 sec)
mysql> -- the leap value with seconds=60 is invalid
mysql> SELECT * FROM t1 WHERE ts = '2008-12-31 23:59:60';
Empty set, 2 warnings (0.00 sec)
lc_time_names控制了日期,月份星期的顯示語言,會影響DATA_FORMAT(),DAYNAME(),MONTHNAME()的輸出。但是lc_time_names不影響STR_TO_DATE(),GET_FORMAT()。format雖然不受lc_time_names影響,但是通過傳入參數可以影響結果。
mysql> SET NAMES 'utf8';
Query OK, 0 rows affected (0.09 sec)
mysql> SELECT @@lc_time_names;
+-----------------+
| @@lc_time_names |
+-----------------+
| en_US |
+-----------------+
1 row in set (0.00 sec)
mysql> SELECT DAYNAME('2010-01-01'), MONTHNAME('2010-01-01');
+-----------------------+-------------------------+
| DAYNAME('2010-01-01') | MONTHNAME('2010-01-01') |
+-----------------------+-------------------------+
| Friday | January |
+-----------------------+-------------------------+
1 row in set (0.00 sec)
mysql> SELECT DATE_FORMAT('2010-01-01','%W %a %M %b');
+-----------------------------------------+
| DATE_FORMAT('2010-01-01','%W %a %M %b') |
+-----------------------------------------+
| Friday Fri January Jan |
+-----------------------------------------+
1 row in set (0.00 sec)
mysql> SET lc_time_names = 'es_MX';
Query OK, 0 rows affected (0.00 sec)
mysql> SELECT @@lc_time_names;
+-----------------+
| @@lc_time_names |
+-----------------+
| es_MX |
+-----------------+
1 row in set (0.00 sec)
mysql>