當運算子與不同類型的運算元一起使用時,會發生類型轉換以使運算元相容。某些轉換是隱含發生的。例如,MySQL 會在必要時自動將字串轉換為數字,反之亦然。
mysql> SELECT 1+'1';
-> 2
mysql> SELECT CONCAT(2,' test');
-> '2 test'
也可以使用 CAST()
函數明確地將數字轉換為字串。轉換會在使用 CONCAT()
函數時隱含發生,因為它預期字串引數。
mysql> SELECT 38.8, CAST(38.8 AS CHAR);
-> 38.8, '38.8'
mysql> SELECT 38.8, CONCAT(38.8);
-> 38.8, '38.8'
請參閱本節後續內容,以取得關於隱含數字到字串轉換的字元集資訊,以及適用於 CREATE TABLE ... SELECT
陳述式的修改規則。
以下規則說明比較運算如何發生轉換
如果一個或兩個引數為
NULL
,則比較結果為NULL
,但NULL
安全的<=>
相等比較運算子除外。對於NULL <=> NULL
,結果為 true。不需要轉換。如果比較運算中的兩個引數都是字串,則會將它們視為字串進行比較。
如果兩個引數都是整數,則會將它們視為整數進行比較。
如果十六進位值未與數字進行比較,則會將它們視為二進位字串。
如果其中一個引數是
TIMESTAMP
或DATETIME
欄,而另一個引數是常數,則在執行比較之前,會將常數轉換為時間戳記。這麼做是為了更符合 ODBC 的規範。這不會針對IN()
的引數執行。為了安全起見,在進行比較時,請務必使用完整的日期時間、日期或時間字串。例如,為了在使用日期或時間值時透過BETWEEN
獲得最佳結果,請使用CAST()
明確地將值轉換為所需的資料類型。來自資料表或資料表的單列子查詢不被視為常數。例如,如果子查詢傳回要與
DATETIME
值比較的整數,則比較會以兩個整數進行。不會將整數轉換為時間值。若要將運算元比較為DATETIME
值,請使用CAST()
明確地將子查詢值轉換為DATETIME
。如果其中一個引數是十進位值,則比較取決於另一個引數。如果另一個引數是十進位或整數值,則會將引數比較為十進位值;如果另一個引數是浮點值,則會將引數比較為浮點值。
在所有其他情況下,會將引數比較為浮點 (雙精確度) 數字。例如,字串和數值運算元的比較會以浮點數的比較進行。
如需關於將值從一種時間類型轉換為另一種時間類型的資訊,請參閱 第 13.2.8 節「日期和時間類型之間的轉換」。
JSON 值的比較會分兩個層級進行。第一個層級的比較基於所比較值的 JSON 類型。如果類型不同,則比較結果僅由哪個類型具有較高的優先順序來決定。如果兩個值具有相同的 JSON 類型,則會使用類型特定的規則發生第二個層級的比較。對於 JSON 和非 JSON 值的比較,會將非 JSON 值轉換為 JSON,並將值比較為 JSON 值。如需詳細資訊,請參閱 JSON 值的比較和排序。
以下範例說明字串轉換為數字以進行比較運算
mysql> SELECT 1 > '6x';
-> 0
mysql> SELECT 7 > '6x';
-> 1
mysql> SELECT 0 > 'x6';
-> 0
mysql> SELECT 0 = 'x6';
-> 1
當字串欄位與數字進行比較時,MySQL無法使用欄位上的索引來快速查找值。如果 str_col
是一個已索引的字串欄位,當執行以下語句中的查找時,則無法使用索引。
SELECT * FROM tbl_name WHERE str_col=1;
原因是有許多不同的字串可以轉換為值 1
,例如 '1'
、' 1'
或 '1a'
。
浮點數與 INTEGER
類型的大數值之間的比較是近似的,因為整數在比較之前會被轉換為雙精度浮點數,而雙精度浮點數無法精確地表示所有 64 位元的整數。例如,整數值 253 + 1 無法以浮點數表示,並且在進行浮點數比較之前會根據平台四捨五入為 253 或 253 + 2。
為了說明這一點,以下比較中只有第一個比較結果是相等的值,但兩個比較都會返回 true (1)。
mysql> SELECT '9223372036854775807' = 9223372036854775807;
-> 1
mysql> SELECT '9223372036854775807' = 9223372036854775806;
-> 1
當字串轉換為浮點數和整數轉換為浮點數時,它們不一定會以相同的方式發生。整數可能會由 CPU 轉換為浮點數,而字串則會在涉及浮點數乘法的運算中逐位轉換。此外,結果還會受到電腦架構或編譯器版本或最佳化層級等因素的影響。避免此類問題的一種方法是使用 CAST()
,這樣值就不會隱式地轉換為浮點數。
mysql> SELECT CAST('9223372036854775807' AS UNSIGNED) = 9223372036854775806;
-> 0
有關浮點數比較的更多資訊,請參閱 第 B.3.4.8 節「浮點數值的問題」。
伺服器包含 dtoa
,這是一個轉換函式庫,為改進字串或 DECIMAL
值與近似值(FLOAT
/DOUBLE
)數字之間的轉換提供了基礎。
跨平台的一致轉換結果,例如消除了 Unix 與 Windows 轉換之間的差異。
在結果先前未提供足夠精度的情況下,例如對於接近 IEEE 極限的值,可以精確地表示值。
以盡可能高的精度將數字轉換為字串格式。
dtoa
的精度始終與標準 C 函式庫的精度相同或更高。
由於此函式庫產生的轉換在某些情況下與非 dtoa
結果不同,因此依賴先前結果的應用程式可能存在不相容性。例如,依賴先前轉換的特定精確結果的應用程式可能需要進行調整以適應額外的精度。
dtoa
函式庫提供的轉換具有以下屬性。D
代表具有 DECIMAL
或字串表示形式的值,而 F
代表以原生二進制 (IEEE) 格式表示的浮點數。
F
->D
轉換以盡可能高的精度完成,返回D
作為最短的字串,當重新讀取並四捨五入到 IEEE 指定的原生二進制格式中的最接近值時,會產生F
。D
->F
轉換的完成方式為使F
是輸入十進制字串D
最接近的原生二進制數。
這些屬性表示 F
-> D
-> F
轉換是無損的,除非 F
是 -inf
、+inf
或 NaN
。不支援後者,因為 SQL 標準將它們定義為 FLOAT
或 DOUBLE
的無效值。
對於 D
-> F
-> D
轉換,無損的充分條件是 D
使用 15 位或更少的精度數字,不是非正規化的值、-inf
、+inf
或 NaN
。在某些情況下,即使 D
具有超過 15 位的精度,轉換也是無損的,但情況並非總是如此。
將數值或時間值隱式轉換為字串會產生一個具有字元集和排序規則的值,該字元集和排序規則由 character_set_connection
和 collation_connection
系統變數確定。(這些變數通常使用 SET NAMES
進行設定。有關連線字元集的資訊,請參閱 第 12.4 節「連線字元集和排序規則」。)
這表示此類轉換會產生字元(非二進制)字串(CHAR
、VARCHAR
或 LONGTEXT
值),除非連線字元集設定為 binary
。在這種情況下,轉換結果是一個二進制字串(BINARY
、VARBINARY
或 LONGBLOB
值)。
對於整數表達式,前面關於表達式評估的說明對於表達式賦值的適用方式略有不同;例如,在如下陳述式中:
CREATE TABLE t SELECT integer_expr;
在這種情況下,表達式產生的欄位中的表格具有 INT
或 BIGINT
類型,具體取決於整數表達式的長度。如果表達式的最大長度不適合 INT
,則會改用 BIGINT
。長度取自 SELECT
結果集元數據的 max_length
值(請參閱 C API 基本資料結構)。這表示您可以透過使用足夠長的表達式來強制使用 BIGINT
而不是 INT
。
CREATE TABLE t SELECT 000000000000000000000;