天天看點

[MySQL Reference Manual] 10 全球化 10.全球化

本章主要介紹全球化,包含國際化和本地化,的一些問題:

·         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&gt; mysqld --character-set-server=latin1

shell&gt; mysqld --character-set-server=latin1 \

           --collation-server=latin1_swedish_ci

如果要修改預設的服務級的字元集和排序規則,可以通過重編譯源代碼進行。

shell&gt; cmake . -DDEFAULT_CHARSET=latin1

shell&gt; 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&gt; SET NAMES latin1;

Query OK, 0 rows affected (0.01 sec)

mysql&gt; SELECT HEX('à\n'), HEX(_sjis'à\n');

+------------+-----------------+

| HEX('à\n') | HEX(_sjis'à\n') |

| E00A       | E00A            |

1 row in set (0.00 sec)

mysql&gt; SET NAMES sjis;

Query OK, 0 rows affected (0.00 sec)

mysql&gt; 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&gt; 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&gt; 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&gt; 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&gt; SET NAMES latin1 COLLATE latin1_bin;

Query OK, 0 rows affected (0.02 sec)

mysql&gt; SELECT LOWER('aA'), UPPER('zZ');

+-------------+-------------+

| LOWER('aA') | UPPER('zZ') |

| aa          | ZZ          |

1 row in set (0.13 sec)

在binary strings中是不能轉化的:

mysql&gt; SET NAMES binary;

mysql&gt; SELECT LOWER('aA'), LOWER(CONVERT('aA' USING latin1));

+-------------+-----------------------------------+

| LOWER('aA') | LOWER(CONVERT('aA' USING latin1)) |

| aA          | aa                                |

Nonbinary strings所有的排序規則有PADSPACE行為。

mysql&gt; SET NAMES utf8 COLLATE utf8_bin;

mysql&gt; SELECT 'a ' = 'a';

+------------+

| 'a ' = 'a' |

|          1 |

但是binary string不行

|          0 |

CHAR(N)儲存nonbinary strings資料,當插入長度不足N會以空格插入。

binary(N)儲存binary string資料,會以0x00填充。

mysql&gt; CREATE TABLE t1 (

    -&gt;   a CHAR(10) CHARACTER SET utf8 COLLATE utf8_bin,

    -&gt;   b BINARY(10)

    -&gt; );

Query OK, 0 rows affected (0.09 sec)

mysql&gt; INSERT INTO t1 VALUES ('a','a');

Query OK, 1 row affected (0.01 sec)

mysql&gt; 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&gt; SELECT SCHEMA_NAME FROM INFORMATION_SCHEMA.SCHEMATA

    -&gt; WHERE SCHEMA_NAME = 'test';

+-------------+

| SCHEMA_NAME |

| test        |

1 row in set (0.01 sec)

    -&gt; WHERE SCHEMA_NAME = 'TEST';

Empty set (0.00 sec)

在windows下:

| TEST        |

如果列的排序規則和想到的不同,可以使用COLLATE語句顯示指定一個排序規則:

    -&gt; WHERE SCHEMA_NAME COLLATE utf8_general_ci = 'test';

    -&gt; 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&gt; 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&gt; mysql_tzinfo_to_sql /usr/share/zoneinfo | mysql -u root mysql

當時區被修改的時候,應用程式還是使用老的時區,為了跟上,确定系統使用的時區資訊是很有必要的。對于mysql有2個方式可以用于跟上時區:

·           如果時區設定為‘system’那麼作業系統的時區會影響mysql服務的事務。

·           如果實在/ect/localtime時區檔案中替換,你就應該重新開機mysqld才能更新修改後的時區。

如果使用命名時區,那麼要保證時區表中的資料時最新的。若系統有自己的時區資訊,那麼系統的時區資訊被更新的時候,要保證mysql内的時區資訊也要被更新。mysqld會cache時區資訊是以更新後需要重新開機服務。如果你要使用命名時區但是不确定有沒有,那麼先檢視時區表。

mysql&gt; 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&gt; 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&gt; 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。

    -&gt;   a INT,

    -&gt;   ts TIMESTAMP DEFAULT NOW(),

    -&gt;   PRIMARY KEY (ts)

mysql&gt; -- change to UTC

mysql&gt; SET time_zone = '+00:00';

mysql&gt; -- Simulate NOW() = '2008-12-31 23:59:59'

mysql&gt; SET timestamp = 1230767999;

mysql&gt; INSERT INTO t1 (a) VALUES (1);

Query OK, 1 row affected (0.00 sec)

mysql&gt; -- Simulate NOW() = '2008-12-31 23:59:60'

mysql&gt; SET timestamp = 1230768000;

mysql&gt; INSERT INTO t1 (a) VALUES (2);

mysql&gt; -- values differ internally but display the same

mysql&gt; 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&gt; -- only the non-leap value matches

mysql&gt; SELECT * FROM t1 WHERE ts = '2008-12-31 23:59:59';

+------+---------------------+

| a    | ts                  

|    1 | 2008-12-31 23:59:59 |

mysql&gt; -- the leap value with seconds=60 is invalid

mysql&gt; 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&gt; SET NAMES 'utf8';

mysql&gt; SELECT @@lc_time_names;

+-----------------+

| @@lc_time_names |

| en_US           |

mysql&gt; SELECT DAYNAME('2010-01-01'), MONTHNAME('2010-01-01');

+-----------------------+-------------------------+

| DAYNAME('2010-01-01') | MONTHNAME('2010-01-01') |

| Friday                | January                 |

mysql&gt; SELECT DATE_FORMAT('2010-01-01','%W %a %M %b');

+-----------------------------------------+

| DATE_FORMAT('2010-01-01','%W %a %M %b') |

| Friday Fri January Jan                  |

mysql&gt; SET lc_time_names = 'es_MX';

| es_MX           |

mysql&gt;