本章主要介紹全球化,包含國際化和本地化,的一些問題:
· MySQL在語句中支援的字元集
· 如何為服務配置不同的字元集
· 選擇錯誤資訊的語言
· 如何設定服務的時區和每個連接配接的時區
· 選擇本土化的日期和月份名
<a href="#_Toc407004104">10.全球化... 1</a>
<a href="#_Toc407004105">10.1 字元集的支援... 2</a>
<a href="#_Toc407004106">10.1.1 字元集和排序規則... 2</a>
<a href="#_Toc407004107">10.1.2 mysql中的字元集和排序規則... 3</a>
<a href="#_Toc407004108">10.1.3 制定字元集和排序規則... 3</a>
<a href="#_Toc407004109">10.1.3.1 服務字元集和排序規則... 3</a>
<a href="#_Toc407004110">10.1.3.2 資料庫級字元集和排序規則... 3</a>
<a href="#_Toc407004111">10.1.3.3 表的字元集和排序規則... 4</a>
<a href="#_Toc407004112">10.1.3.4 列的字元集和排序規則... 4</a>
<a href="#_Toc407004113">10.1.3.5 字元串常量的字元集和排序規則... 5</a>
<a href="#_Toc407004114">10.1.3.6 National Character Set6</a>
<a href="#_Toc407004115">10.1.3.7 字元集和排序規則設定的例子... 6</a>
<a href="#_Toc407004116">10.1.3.8 和其他資料的相容... 6</a>
<a href="#_Toc407004117">10.1.4 連接配接的字元集和排序規則... 7</a>
<a href="#_Toc407004118">10.1.5 為應用程式配置字元集和排序規則... 8</a>
<a href="#_Toc407004119">10.1.5.1 為每個資料指定字元集和排序規則... 8</a>
<a href="#_Toc407004120">10.1.5.2 在服務啟動是配置字元集... 8</a>
<a href="#_Toc407004121">10.1.5.3 在Mysql配置的時候設定字元集和排序規則... 8</a>
<a href="#_Toc407004122">10.1.6 錯誤資訊的字元集... 9</a>
<a href="#_Toc407004123">10.1.7 排序規則... 9</a>
<a href="#_Toc407004124">10.1.7.1 排序規則名... 9</a>
<a href="#_Toc407004125">10.1.7.2 在語句中使用排序規則... 9</a>
<a href="#_Toc407004126">10.1.7.3 COLLATE子句... 10</a>
<a href="#_Toc407004127">10.1.7.4 排序規則必須要一個正确的字元集... 10</a>
<a href="#_Toc407004128">10.1.7.5 表達式中的排序規則... 10</a>
<a href="#_Toc407004129">10.1.7.6 _bin和binary. 11</a>
<a href="#_Toc407004130">10.1.7.7 BINARY操作... 13</a>
<a href="#_Toc407004131">10.1.7.8 Collation的影響例子... 13</a>
<a href="#_Toc407004132">10.1.7.9 排序規則和INFORMATION_SCHEMA查找... 13</a>
<a href="#_Toc407004133">10.1.8 字元目錄(String Repertoire)15</a>
<a href="#_Toc407004134">10.1.9 受字元集影響的操作... 16</a>
<a href="#_Toc407004135">10.1.9.1 結果字元串... 16</a>
<a href="#_Toc407004136">10.1.9.2 CONVERT()和CAST()16</a>
<a href="#_Toc407004137">10.1.9.3 SHOW語句和INFORMATION_SCHEMA.. 16</a>
<a href="#_Toc407004138">10.1.10 Unicode支援... 16</a>
<a href="#_Toc407004139">10.1.10.1 ucs2字元集... 17</a>
<a href="#_Toc407004140">10.1.10.2 utf16字元集... 17</a>
<a href="#_Toc407004141">10.1.10.3 utf16le字元集... 17</a>
<a href="#_Toc407004142">10.1.10.4 utf32字元集... 17</a>
<a href="#_Toc407004143">10.1.10.5 utf8字元集... 17</a>
<a href="#_Toc407004144">10.1.10.6 utf8mb3字元集... 18</a>
<a href="#_Toc407004145">10.1.10.7 utf8mb4字元集... 18</a>
<a href="#_Toc407004146">10.1.11 更新unicode的支援... 18</a>
<a href="#_Toc407004147">10.1.12 中繼資料為utf8. 19</a>
<a href="#_Toc407004148">10.1.13 列字元集轉化... 19</a>
<a href="#_Toc407004149">10.1.14 MySQL支援的字元集和排序規則... 20</a>
<a href="#_Toc407004150">10.2 設定錯誤資訊語言... 20</a>
<a href="#_Toc407004151">10.3 增加一個字元集... 20</a>
<a href="#_Toc407004152">10.4 為字元集增加一個排序規則... 20</a>
<a href="#_Toc407004153">10.5 配置字元集... 20</a>
<a href="#_Toc407004154">10.6 MySQL時區的支援... 20</a>
<a href="#_Toc407004155">10.6.1 跟上時區修改... 21</a>
<a href="#_Toc407004156">10.6.2 時區閏秒支援(Time Zone Leap Seconad Support)22</a>
<a href="#_Toc407004157">10.7 MySQL Server本地化支援... 23</a>
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 --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
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)
[COLLATE collation_name]]
ALTER TABLE tbl_name
[COLLATE collation_name]
表選擇字元集和排序規則和資料庫一緻。
如果建立表時,表沒有指定列的字元集和排序規則,那麼就用表的字元集和排序規則。
列的字元集和排序規則通過create table和alter table來指定。
col_name {CHAR | VARCHAR | TEXT} (col_length)
[CHARACTER SET charset_name]
col_name {ENUM | SET} (val_list)
如:
CREATE TABLE t1
(
col1 VARCHAR(5)
CHARACTER SET latin1
COLLATE latin1_german1_ci
);
ALTER TABLE t1 MODIFY
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.設定列和表的字元集和排序規則
c1 CHAR(10) CHARACTER SET latin1 COLLATE latin1_german1_ci
) DEFAULT CHARACTER SET latin2 COLLATE latin2_bin;
2.列不帶排序規則
c1 CHAR(10) CHARACTER SET latin1
) DEFAULT CHARACTER SET latin1 COLLATE latin1_danish_ci;
3.列不帶字元集和排序規則
c1 CHAR(10)
4.資料庫設定排序規則和字元集,表和列不設定
CREATE DATABASE d1
DEFAULT CHARACTER SET latin2 COLLATE latin2_czech_ci;
USE d1;
略
連接配接的字元集和排序規則主要說明一下一些問題:
· 當用戶端發送前語句的時候使用什麼字元集,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 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
ORDER BY k1;
· With GROUP BY:
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
· With WHERE:
SELECT *
FROM t1
WHERE _latin1 'Müller' COLLATE latin1_german2_ci = k;
WHERE k LIKE _latin1 'Müller' COLLATE latin1_german2_ci;
· With HAVING:
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;
mysql> SELECT LOWER('aA'), LOWER(CONVERT('aA' USING latin1));
+-------------+-----------------------------------+
| LOWER('aA') | LOWER(CONVERT('aA' USING latin1)) |
| aA | aa |
Nonbinary strings所有的排序規則有PADSPACE行為。
mysql> SET NAMES utf8 COLLATE utf8_bin;
mysql> SELECT 'a ' = 'a';
+------------+
| 'a ' = 'a' |
| 1 |
但是binary string不行
| 0 |
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 |
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)
-> WHERE SCHEMA_NAME = 'TEST';
Empty set (0.00 sec)
在windows下:
| TEST |
如果列的排序規則和想到的不同,可以使用COLLATE語句顯示指定一個排序規則:
-> WHERE SCHEMA_NAME COLLATE utf8_general_ci = 'test';
-> WHERE SCHEMA_NAME COLLATE utf8_general_ci = 'TEST';
當然也可以使用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:
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,那麼可以通過以下語句去轉化:
如果類型是binary(50),那麼可以轉化為char(50)但是,可能會出現0x00在末尾可能無法描述,需要使用trim();
如果表t有col1 char(50) character set latin1,要轉化為utf8,可以直接:
預設mysql的錯誤資訊是英語,但是可以指定其他語言。
在mysql 5.6中錯誤資訊在以下2個目錄下去查找:
· 會從lc_messages_dir和lc_messages 2個系統變量上去查找,使用如下:
· 如果找不到,那麼會放棄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 |
更新後:
| 2007-03-11 01:00:00 |
如果出現閏秒(23:59:60)情況會使用59:59。
-> a INT,
-> ts TIMESTAMP DEFAULT NOW(),
-> PRIMARY KEY (ts)
mysql> -- change to UTC
mysql> SET time_zone = '+00:00';
mysql> -- Simulate NOW() = '2008-12-31 23:59:59'
mysql> SET timestamp = 1230767999;
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;
mysql> INSERT INTO t1 (a) VALUES (2);
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 |
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';
mysql> SELECT @@lc_time_names;
+-----------------+
| @@lc_time_names |
| en_US |
mysql> SELECT DAYNAME('2010-01-01'), MONTHNAME('2010-01-01');
+-----------------------+-------------------------+
| DAYNAME('2010-01-01') | MONTHNAME('2010-01-01') |
| Friday | January |
mysql> SELECT DATE_FORMAT('2010-01-01','%W %a %M %b');
+-----------------------------------------+
| DATE_FORMAT('2010-01-01','%W %a %M %b') |
| Friday Fri January Jan |
mysql> SET lc_time_names = 'es_MX';
| es_MX |
mysql>