原文地址:https://www.cnblogs.com/blankqdb/archive/2012/11/03/blank_qdb.htmlphp
1. UNSIGNEDhtml
UNSIGNED屬性就是將數字類型無符號化,與C、C++這些程序語言中的unsigned含義相同。例如,INT的類型範圍是-2 147 483 648 ~ 2 147 483 647, INT UNSIGNED的範圍類型就是0 ~ 4 294 967 295。mysql
在MYSQL中整型範圍:linux
類型 大小 範圍(有符號) 範圍(無符號) 用途sql
TINYINT 1 字節 (-128,127) (0,255) 小整數值數據庫
SMALLINT 2 字節 (-32 768,32 767) (0,65 535) 大整數值windows
MEDIUMINT 3 字節 (-8 388 608,8 388 607) (0,16 777 215) 大整數值數據庫設計
INT或INTEGER 4 字節 (-2 147 483 648,2 147 483 647) (0,4 294 967 295) 大整數值操作系統
源文檔 <http://www.cnblogs.com/bukudekong/archive/2011/06/27/2091590.html>設計
看起來這是一個不錯的屬性選項,特別是對於主鍵是自增加的類型,由於通常來講,用戶都但願主鍵是非負數。然而在實際使用中,UNSIGNED可能會帶來一些負面的影響,示例以下:
mysql> CREATE TABLE t ( a INT UNSIGNED, b INT UNSIGNED )
ENGINE=INNODB;
Query OK, 0 rows affected (0.06 sec)
mysql> INSERT INTO t SELECT 1,2;
Query OK, 1 row affected (0.00 sec)
Records: 1 Duplicates: 0 Warnings: 0
mysql> SELECT * FROM t\G;
*************************** 1. row ***************************
a: 1
b: 2
1 row in set (0.00 sec)
咱們建立了一個表t,存儲引擎爲InnoDB。表t上有兩個UNSIGNED的INT類型。輸入(1,2)這一行數據,目前看來都沒有問題,接着運行以下語句:
SELECT a - b FROM t
這時結果會是什麼呢?會是-1嗎?答案是不肯定的,能夠是-1,也能夠是一個很大的正值,還可能會報錯。在Mac操做系統中(windows中也會),MySQL數據庫提示以下錯誤:
mysql> SELECT a-b FROM t;
ERROR 1690 (22003): BIGINT UNSIGNED value is out of range in '(`test`.`t`.`a` - `test`.`t`.`b`)'
這個錯誤乍看起來很是奇怪,提示BIGINT UNSIGNED超出了範圍,可是咱們採用的類型都是INT UNSIGNED啊!而在另外一臺Linux操做系統中,運行的結果倒是:
mysql> SELECT a -b FROM t\G;
*************************** 1. row ***************************
a - b: 4294967295
1 row in set (0.00 sec)
在發生上述這個問題的時候,有開發人員跑來和筆者說,他發現了一個MySQL的Bug,MySQL怎麼會這麼「傻」呢?在聽完他的敘述以後,我寫了以下的代碼並告訴他,這不是MySQL的Bug,C語言一樣也會這麼「傻」。
#include
int main(){
unsigned int a;
unsigned int b;
a = 1;
b = 2;
printf(a - b: %d\n,a-b);
printf(a - b: %u\n,a-b);
return 1;
}
上述代碼的運行結果是:
a - b: -1
a - b: 4294967295
能夠看到,在C語言中a-b也能夠返回一個很是巨大的整型數,這個值是INT UNSIGNED的最大值。難道C語言也發生了Bug?這怎麼可能呢?
在實際的使用過程當中,MySQL給開發人員的印象就是存在不少Bug,只要結果出乎預料或者有開發人員不能理解的狀況發生時,他們每每把這歸咎於MySQL的 Bug。和其餘數據庫同樣,MySQL的確存在一些Bug,其實並非MySQL數據庫的Bug比較多,去看一下Oracle RAC的Bug,那可能就更多了,它但是Oracle的一款旗艦產品。所以,不能簡單地認爲這個問題是MySQL的Bug。
對於上述這個問題,正如上述所分析的,若是理解整型數在數據庫中的表示方法,那麼這些就很是好理解了,這也是爲何以前強調須要看一些計算機組成原理方面相關書籍的緣由。將上面的C程序作一些修改:
#include
int main(){
unsigned int a;
unsigned int b;
a = 1;
b = 2;
printf(a - b: %d,%x\n,a-b,a-b);
printf(a - b: %u,%x\n,a-b,a-b);
return 1;
}
此次不只打印出a-b的結果,也打印出a-b的十六進制結果,運行程序後的結果以下所示:
a - b: -1,ffffffff
a - b: 4294967295,ffffffff
能夠看到結果都是0xFFFFFFFF,只是0xFFFFFFFF能夠表明兩種值:對於無符號的整型值,其是整型數的最大值,即4 294 967 295;對於有符號的整型數來講,第一位表明符號位,若是是1,表示是負數,這時應該是取反加1獲得負數值,即-1。
這個問題的核心是,在MySQL數據庫中,對於UNSIGNED數的操做,其返回值都是UNSIGNED的。而正負數這個問題在《MySQL技術內幕:InnoDB存儲引擎》中有更深刻的分析,有興趣的能夠進一步研究。
那麼,怎麼得到-1這個值呢?這並非一件難事,只要對SQL_MODE這個參數進行設置便可,例如:
mysql>SET sql_mode='NO_UNSIGNED_SUBTRACTION';
Query OK, 0 rows affected (0.00 sec)
mysql> SELECT a-b FROM t\G;
*************************** 1. row ***************************
a-b: -1
1 row in set (0.00 sec)
後面會對SQL_MODE進一步討論,這裏不進行深刻的討論。筆者我的的見解是儘可能不要使用UNSIGNED,由於可能會帶來一些意想不到的效果。另外,對於INT類型可能存放不了的數據,INT UNSIGNED一樣可能存放不了,與其如此,還不如在數據庫設計階段將INT類型提高爲BIGINT類型。
以上文字摘自<http://tech.it168.com/a2012/0808/1382/000001382732.shtml>
本人遇到的相似問題:(linux上)
當(a-b)在where子句後時也會出現相同的狀況
如下是php使用Mysql查詢的結果(每組的第一行是第二行[1]-[2]的結果)
86374
a b
Array ( [1] => 1351843032 [2] => 1351756658 )
-2567
Array ( [1] => 1351843032 [2] => 1351845599 )
86374
Array ([1] => 1351843032 [2] => 1351756658 )
86374
Array ( [1] => 1351843032 [2] => 1351756658 )
-105849
Array ( [1] => 1351650809 [2] => 1351756658 )
86374
Array ( [1] => 1351843032 [2] => 1351756658 )
86374
Array ( [1] => 1351843032 [2] => 1351756658 )
下面在mysql語句中查詢select * from table where (a-b)>86374;
結果(按正常思路來說,結果應該爲空,但在Linux是卻現出如下結果 ):
Array ( [1] => 1351843032 [2] => 1351845599 )
Array ( [1] => 1351650809 [2] => 1351756658 )
而這個結果恰是[1]-[2]爲負數的那兩行。
結論:若是使用unsigne而且在where子句後出現兩列相減值小於0((a-b)<0),在查詢時,linux上的Mysql會將負數轉換成unsigned後再進行查詢( (-2576+4294967295+1)>86374, (-105849+4294967295+1)>86374 )。