MySQL學習之路5
資料型別和運算子
1 . MySQL資料型別介紹
MySQL主要支援的資料型別有:數值型別、日期/時間型別、字串型別。
(1)數值資料型別:包括整數型別TINYINT、SMALLINT、MEDIUMINT、INT、BIGINT、浮點小數資料型別FLOAT和DOUBLE、定點小數型別DECIMAL。
(2)日期/時間型別:包括YEAR、TIME、DATE、DATETIME和TIMESTAMP。
(3)字串型別:包括CHAR、VARCHAR、BINARY、VARBINARY、BLOB、TEXT、ENUM和SET等。
1.1 整數型別
整數型別的屬性欄位可以新增AUTO_INCREMENT自增約束條件。
MySQL中的整數型資料型別:
型別名稱 | 說明 | 儲存需求 |
---|---|---|
TINYINT | 很小的整數 | 1個位元組(8 bits) |
SMALLINT | 小的整數 | 2個位元組 |
MEDIUMINT | 中等大小的整數 | 3個位元組 |
INT(INTEGER)INT | 普通大小的整數 | 4個位元組 |
BIGINT | 大整數 | 8個位元組 |
不同整數型別的取值範圍
資料型別 | 有符號 | 無符號 |
---|---|---|
TINYINT | -128~127 | 0~255 |
SMALLINT | -32768~32767 | 0~65535 |
MEDIUMINT | -8388608~8388607 | 0~16777215 |
INT(INTEGER)INT | -2147483648~2147482617 | 0~4294967295 |
BIGINT | -9223372036854775808~9223372036854775807 | 0~18446744073709551615 |
下面你需要注意的地方是:如INT(11)裡的111表示的是該資料型別指定的顯示寬度。顯示寬度和資料型別的取值範圍是無關的 。顯示寬度只是指明MySQL最大可能顯示的數字個數,數值的位數小於指定的寬度時會由空格填充;如果插入大於顯示寬度的值,只要該值不超過該型別整數的取值範圍,數值一樣可以插入並能夠顯示出來。
例:建立表rmp1,其中欄位x、y、z、m、n資料型別依次為TINYINT、SMALLINT、MEDIUMINT、INT、BIGINT,SQL語句如下:
mysql> CREATE TABLE rmp1(x TINYINT, y SMALLINT, z MEDIUMINT, m INT, n BIGINT);
Query OK, 0 rows affected (2.13 sec)
查看錶結構:
mysql> DESC rmp1;
+-------+--------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+--------------+------+-----+---------+-------+
| x | tinyint(4) | YES | | NULL | |
| y | smallint(6) | YES | | NULL | |
| z | mediumint(9) | YES | | NULL | |
| m | int(11) | YES | | NULL | |
| n | bigint(20) | YES | | NULL | |
+-------+--------------+------+-----+---------+-------+
5 rows in set (0.19 sec)
可以看到系統給每一個欄位新增不同的預設使用寬度。
注:顯示寬度只用於顯示,並不能限制取值範圍和佔用空間,如:INT(3)會佔用4個位元組的儲存空間,但是允許的最大值是INT允許的最大值。
1.2浮點數型別和定點數型別
浮點型別有兩種:單精度浮點數型別(FLOAT)和雙精度浮點型別(DOUBLE)。
定點型別:DECIMAL。
這兩種型別均可以使用(M,N)表示,M(精度)表示總共的位數;N(標度)表示小數的位數。
MySQL中的小數型別
型別名稱 | 說明 | 儲存需求 |
---|---|---|
FLOAT | 單精度浮點數 | 4個位元組 |
DOUBLE | 雙精度浮點數 | 8個位元組 |
DECIMAL (M,D) DEC | 壓縮的“嚴格”定點數 | M+2個位元組 |
資料型別 | 有符號 | 無符號 |
---|---|---|
FLOAT | -3.402823466E+38~-1.175494351E-38 | 0和1.175494351E-38~3.402823466E+38 |
DOUBLE | -1.7976931348623157E+308~-2.2250738585072014E-308 | 0和2.2250738585072014E-308~1.7976931348623157E+308 |
提示:如果使用者指定的精度超出精度範圍,則會四捨五入進行處理。
例:建立表tmp2,其中欄位x、y、z資料型別依次為FLOAT(5,1)、DOUBLE(5,1)和DECIMAL(5,1),向表中插入資料5.12,5.15和5.123,SQL語句如下:
mysql> CREATE TABLE tmp2(x FLOAT(5,1), y DOUBLE(5,1), z DECIMAL(5,1));
Query OK, 0 rows affected (0.62 sec)
mysql> INSERT INTO tmp2 VALUES(5.12,5.15,5.123);
Query OK, 1 row affected, 1 warning (0.22 sec)
mysql> SHOW WARNINGS;
+-------+------+----------------------------------------+
| Level | Code | Message |
+-------+------+----------------------------------------+
| Note | 1265 | Data truncated for column 'z' at row 1 |
+-------+------+----------------------------------------+
1 row in set (0.14 sec)
可以看到FLOAT和DOUBLE在進行四捨五入時沒有給出警告,但給出了z欄位數值被截斷警告。
檢視結果:
mysql> SELECT * FROM tmp2;
+------+------+------+
| x | y | z |
+------+------+------+
| 5.1 | 5.2 | 5.1 |
+------+------+------+
1 row in set (0.18 sec)
FLOAT和DOUBLE在不指定精度時,預設會按照實際的精度,而DECIMAL在不指定精度時會預設(10,0)。
注:浮點數能表示更大的資料範圍,但會引起精度問題。
1.3日期與時間型別
MySQL中表示日期的資料型別:DATETIME、DATETIME、STAMP、TIME和YEAR。
型別名稱 | 日期格式 | 日期範圍 | 儲存需求 |
---|---|---|---|
YEAR | YYYY | 1901~2155 | 1位元組 |
TIME | HH:MM:SS | -838:59:59~838:59:59 | 3位元組 |
DATE | YYYY-MM-DD | 1000-01-01~9999-12-31 | 3位元組 |
DATETIME | YYYY-MM-DD HH-MM-SS | 1000-01-01 00:00:00~9999-12-31 23:59:59 | 8位元組 |
TIMESTAMP | YYYY-MM-DD HH:MM:SS | 1970-01-01 00:00:01 UTC ~ 2038-01-19 03:14:07 UTC | 4位元組 |
1.year
可以使用下列格式指定YEAR的值:
- 以4位字串或數字表示,即’YYYY’或者YYYY,範圍:‘1901’~‘2155’.
- 以2位字串格式表示, ‘00’ ~ ‘69’ 和 ‘70’ ~ '99’範圍的值分別被轉換為2000~ 2069和1970~ 1999範圍的YEAR值。'0’與’00’的作用相同,若插入超過取值範圍的值將被轉換為2000。
- 以2位數字表示與以字串格式表示類似。注意:這裡0值會被轉換成0000.
例:建立表tmp3,定義資料型別為YEAR的欄位y,向表中插入值為2010,‘2010’,‘2166’,SQL語句如下:
mysql> CREATE TABLE tmp3(y YEAR);
Query OK, 0 rows affected (1.78 sec)
mysql> INSERT INTO tmp3 values(2010),('2010'),('2166');
ERROR 1264 (22003): Out of range value for column 'y' at row 3
出現錯誤,超出範圍。(這裡與上面筆記所說不相符,大概是MySQL版本的問題)
例:向tmp3表中y欄位插入2位字串表示的YEAR值,分別為‘0’、‘00’、‘77’和‘10’,語句如下:
首先刪除表中資料
mysql> DELETE FROM tmp3;
Query OK, 0 rows affected (0.14 sec)
向表中插入資料
mysql> INSERT INTO tmp3 values('0'),('00'),('77'),('10');
Query OK, 4 rows affected (0.10 sec)
Records: 4 Duplicates: 0 Warnings: 0
檢視結果
mysql> SELECT * FROM tmp3;
+------+
| y |
+------+
| 2000 |
| 2000 |
| 1977 |
| 2010 |
+------+
4 rows in set (0.02 sec)
其他就不一 一展示。
2.TIME
格式:
- ‘D HH:MM:SS’/‘HH:MM:SS’/‘D HH:MM’/‘D HH’/‘SS’。這裡D表示日(0~34),在插入資料庫時,D被轉換為小時儲存,格式為“D*24+HH”。
- ‘HHMMSS’。
例:建立資料表tmp4,定義資料型別為TIME欄位t,向表中插入值’10:05:05’,‘23:23’,‘2 10:10’,‘3 02’,‘10’,SQL語句如下:
mysql> CREATE TABLE tmp4(t TIME);
Query OK, 0 rows affected (0.56 sec)
mysql> INSERT INTO tmp4 VALUES('10:05:05'),('23:23'),('2 10:10'),('3 02'),('10');
Query OK, 5 rows affected (0.14 sec)
Records: 5 Duplicates: 0 Warnings: 0
mysql> SELECT * FROM tmp4;
+----------+
| t |
+----------+
| 10:05:05 |
| 23:23:00 |
| 58:10:00 |
| 74:00:00 |
| 00:00:10 |
+----------+
5 rows in set (0.12 sec)
注:在使用D HH格式時,小時一定要使用雙位數。
例:向表tmp4中插入值’101112’,111213,‘0’,107010,SQL語句如下:
首先刪除資料:
mysql> DELETE FROM tmp4;
Query OK, 5 rows affected (0.18 sec)
向表中插入資料:
mysql> INSERT INTO tmp4 VALUES('10112'),(111213),('0'),(107010);
ERROR 1292 (22007): Incorrect time value: '107010' for column 't' at row 4
可以看到有錯誤產生,即在插入第4條資料時,資料超出了範圍,原因是70超出了60分鐘。
下面使用系統日期函式向TIME欄位插入值。
例:向tmp4插入系統當前時間,SQL語句如下:
mysql> INSERT INTO tmp4 VALUES(CURRENT_TIME),(NOW());
Query OK, 2 rows affected (0.18 sec)
Records: 2 Duplicates: 0 Warnings: 0
mysql> SELECT * FROM tmp4;
+----------+
| t |
+----------+
| 08:43:00 |
| 08:43:00 |
+----------+
2 rows in set (0.00 sec)
1.3DATE型別(3bytes)
-
‘YYYY-MM-DD’ or 'YYYYMMDD’字元格式表示日期,取值範圍:
‘1000-0101’~ ‘9999-12-3’ 。 -
‘YY-MM-DD’~ 'YYMMDD’字元格式表示日期
'00~ 69’表示‘2000 ~ 2069’
'70~99’表示‘1970 ~1999’。 -
YY-MM-DD or YYMMDD數字格式表示日期,範圍與2相似,但是YY-MM-DD需要用雙引號引上。
例:建立資料表tmp5,定義資料型別為DATE的欄位d,向表中插入“YYYY-MM-DD”和“YYYYMMDD”字串格式日期,SQL語句如下:
mysql> CREATE TABLE tmp5(d DATE);
Query OK, 0 rows affected (0.53 sec)
mysql> INSERT INTO tmp5 VALUES('1998-08-08'),('19980808'),('20101010');
Query OK, 3 rows affected (0.06 sec)
檢視結果:
mysql> SELECT * FROM tmp5;
+------------+
| d |
+------------+
| 1998-08-08 |
| 1998-08-08 |
| 2010-10-10 |
+------------+
3 rows in set (0.00 sec)
例:向tmp5表中插入“YY-MM-DD”和“YYMMDD”字串格式日期,SQL 語句如下:
mysql> DELETE FROM tmp5;
Query OK, 3 rows affected (0.06 sec)
mysql> INSERT INTO tmp5 VALUES('99-09-09'),('990909'),('000101'),('111111');
Query OK, 4 rows affected (0.11 sec)
Records: 4 Duplicates: 0 Warnings: 0
mysql> SELECT * FROM tmp5;
+------------+
| d |
+------------+
| 1999-09-09 |
| 1999-09-09 |
| 2000-01-01 |
| 2011-11-11 |
+------------+
4 rows in set (0.00 sec)
例:向tmp5表中插入YY-MM-DD和YYMMDD數字格式日期,SQL語句如下:
mysql> INSERT INTO tmp5 VALUES("990909"),(990909),(000101),(111111);
Query OK, 4 rows affected (0.11 sec)
Records: 4 Duplicates: 0 Warnings: 0
mysql> SELECT * FROM tmp5;
+------------+
| d |
+------------+
| 1999-09-09 |
| 1999-09-09 |
| 2000-01-01 |
| 2011-11-11 |
+------------+
4 rows in set (0.00 sec)
例:向tmp5插入系統當前日期:
mysql> DELETE FROM tmp5;
Query OK, 4 rows affected (0.08 sec)
mysql> INSERT INTO tmp5 VALUES(CURRENT_DATE()),(NOW());
Query OK, 2 rows affected, 1 warning (0.06 sec)
Records: 2 Duplicates: 0 Warnings: 1
mysql> SELECT * FROM tmp5;
+------------+
| d |
+------------+
| 2018-11-30 |
| 2018-11-30 |
+------------+
2 rows in set (0.00 sec)
CURRENT_DATE()只返回當前日期值
NOW()返回日期和時間值,這裡d為DATE型別,故只儲存了DATE部分
提示:MySQL允許不嚴格的語法:任何標點符號都可以用作日期部分之間的間隔符。
1.4DATETIME
格式:
- ‘YYYY-MM-DD HH:MM:SS’、‘YYYYMMDDHHMMSS’字串格式表示,取值範圍‘1000-01-01 00:00:00’~‘9999-12-3 23:59:59’。
- ‘YY-MM-DD HH:MM:SS’、‘YYMMDDHHMMSS’字串格式表示,取值範圍YY表示年值,其取值範圍與前面日期的相同。
- YYYYMMDDHHMMSS、YYMMDDHHMMSS數字格式表示。
例:建立資料表tmp6,定義資料型別為DATETIME的欄位dt,向表中插入日期和時間值(這裡只演示數字格式和插入系統當前日期和時間值)
建立資料表:
mysql> CREATE TABLE tmp6(dt DATETIME);
Query OK, 0 rows affected (0.46 sec)
插入值:
mysql> INSERT INTO tmp6 VALUES(19970823121314),(NOW());
Query OK, 2 rows affected (0.13 sec)
Records: 2 Duplicates: 0 Warnings: 0
檢視值:
mysql> SELECT * FROM tmp6;
+---------------------+
| dt |
+---------------------+
| 1997-08-23 12:13:14 |
| 2018-11-30 14:36:34 |
+---------------------+
2 rows in set (0.07 sec)
MySQL允許不嚴格的語法,實驗:
1
mysql> INSERT INTO tmp6 VALUES('2018$06&18 08\18+50');
ERROR 1292 (22007): Incorrect datetime value: '2018$06&18 0818+50' for column 'dt' at row 1
2
mysql> INSERT INTO tmp6 VALUES('2018$06&18 08/18?50');
Query OK, 1 row affected (0.14 sec)
3
mysql> INSERT INTO tmp6 VALUES('2018$06&18 08\18\15');
ERROR 1292 (22007): Incorrect datetime value: '2018$06&18 081815' for column 'dt' at row
只有第2個可以插入。
5.TIMESTAMP
TIMESTAMP顯示格式與DATETIME相同,日期格式為:YYYY-MM-DD HH:MM:SS。但取值範圍比DATETIME小,其取值範圍為:‘1970-01-01 00:00:01’ UTC ~ ‘2038-01-19 03:14:07’ UTC,UTC:世界標準時間。
例:建立資料表tmp7,向表中插入值:
mysql> CREATE TABLE tmp7(ts TIMESTAMP);
Query OK, 0 rows affected (0.38 sec)
mysql> INSERT INTO tmp7 VALUES('[email protected]@12 [email protected]@12'),(NOW());
Query OK, 2 rows affected (0.15 sec)
Records: 2 Duplicates: 0 Warnings: 0
mysql> SELECT * FROM tmp7;
+---------------------+
| ts |
+---------------------+
| 1997-12-12 12:12:12 |
| 2018-11-30 14:52:11 |
+---------------------+
2 rows in set (0.00 sec)
TIMESTAMP儲存的時間與當前所處的時區有關。
例:向tmp7表中插入當前日期,檢視插入值,將時區改為東10區,再次檢視插入值:
mysql> DELETE FROM tmp7;
Query OK, 2 rows affected (0.13 sec)
mysql> INSERT INTO tmp7 VALUES(NOW());
Query OK, 1 row affected (0.06 sec)
mysql> SELECT * FROM tmp7;
+---------------------+
| ts |
+---------------------+
| 2018-11-30 14:55:07 |
+---------------------+
1 row in set (0.00 sec)
mysql> set time_zone='+10:00';
Query OK, 0 rows affected (0.06 sec)
mysql> SELECT * FROM tmp7;
+---------------------+
| ts |
+---------------------+
| 2018-11-30 16:55:07 |
+---------------------+
1 row in set (0.00 sec)
1.5字串型別
MySQL中的字串型別:
型別名稱 | 說明 | 儲存需求 |
---|---|---|
CHAR(M) | 固定長度非二進位制字串 | M位元組,1<=M<=255 |
VARCHAR(M) | 變長非二進位制字串 | L+1位元組,L<=M,1<=M<=255 |
TINYTEXT | 非常小的非二進位制字串 | L+1位元組,L<2^8 |
TEXT | 小的非二進位制字串 | L+2位元組,L<2^16 |
MEDIUMTEXT | 中等大小的非二進位制字串 | L+3位元組,L<2^24 |
LONGTEXT | 大的非二進位制字串 | L+4位元組,L<2^32 |
ENUM | 列舉型別,只能有一個列舉字串值 | 1或2個位元組,取決於列舉值的數目(最大值65535) |
SET | 一個設定,字串物件可以有0個或多個SET成員 | 1,2,3,4或8個位元組,取決於集合成員的數量(最多64個成員) |
1.CHAR與VARCHAR
CHAR固定長度,當檢索到CHAR值時,尾部的空格將被刪除掉,且無論存入的長度為多少,所佔的空間均為定義時指定的字串列長。
VARCHAR在值儲存和檢索時尾部的空格仍保留,且其定義的列所佔的位元組數為實際長度加1。
例:建立tmp8表,定義欄位ch(CHAR(4)),vch(VARCHAR(4))向表中插入資料“ab ”,SQL語句如下:
mysql> CREATE TABLE tmp8(
-> ch CHAR(4),
-> vch VARCHAR(4)
-> );
Query OK, 0 rows affected (1.51 sec)
mysql> INSERT INTO tmp8 VALUES('ab ','ab ')
-> ;
Query OK, 1 row affected (0.16 sec)
查詢結果:
mysql> SELECT concat('(',ch,')'),concat('(',vch,')') FROM tmp8;
+--------------------+---------------------+
| concat('(',ch,')') | concat('(',vch,')') |
+--------------------+---------------------+
| (ab) | (ab ) |
+--------------------+---------------------+
1 row in set (0.21 sec)
可以看到,ch在儲存值時把尾部空格刪去,而vch仍保留尾部空格。
2.TEXT型別
TEXT列儲存非二進位制字串,如文章內容、評論等。
Text型別有四種:TINYTEXT、TEXT、MEDIUMTEXT、LONGTEXT。
3.ENUM型別
ENUM是一個字串物件,其值為表建立時在列規定中列舉的一列值。
語法格式:欄位名 ENUM('值 1' , '值 2' , ... , '值 n')
每個列舉值均有一個索引值,但是請注意儲存值不是一個十分明智的選擇,故一般儲存索引。
ENUM型別的取值範圍:
值 | 索引 |
---|---|
NULL | NULL |
‘’ | 0 |
first | 1 |
second | 2 |
third | 3 |
例:建立表tmp9,定義ENUM型別的列enm(‘first’ , ‘second’ , ‘third’),檢視列成員的索引值:
mysql> CREATE TABLE tmp9(enm ENUM('first','second','third'));
Query OK, 0 rows affected (0.54 sec)
mysql> INSERT INTO tmp9 values('first'),('second'),('third'),(NULL);
Query OK, 4 rows affected (0.15 sec)
Records: 4 Duplicates: 0 Warnings: 0
mysql> SELECT enm ,enm+0 FROM tmp9;
+--------+-------+
| enm | enm+0 |
+--------+-------+
| first | 1 |
| second | 2 |
| third | 3 |
| NULL | NULL |
+--------+-------+
4 rows in set (0.54 sec)
我試了一下,發現我mysql版本無法輸入‘’,我想應該是需要更高的版本吧!
4.set型別
例:建立表tmp11,定義set型別欄位,取值列表為(‘a’,‘b’,‘c’,‘d’),插入資料(‘a’),(‘a,b,a’),(‘c,a,d’),(‘a,x,b,y’),SQL語句如下:
mysql> CREATE TABLE tmp11(s SET('a','b','c','d'));
Query OK, 0 rows affected (0.37 sec)
mysql> INSERT INTO tmp11 VALUES('a'),('a,b,a'),('c,a,b'),('a,x,b,y');
ERROR 1265 (01000): Data truncated for column 's' at row 4
可以看到由於插入了SET列不支援的型別,出現錯誤。
重新插入
mysql> INSERT INTO tmp11 VALUES('a'),('a,b,a'),('c,a,b');
Query OK, 3 rows affected (0.04 sec)
Records: 3 Duplicates: 0 Warnings: 0
mysql> SELECT * FROM tmp11;
+-------+
| s |
+-------+
| a |
| a,b |
| a,b,c |
+-------+
3 rows in set (0.00 sec)
從結果可以看出,set不允許重複,且有先後順序明確。
1.5 二進位制型別
MySQL支援兩類字元型資料:文字字串、二進位制字串。
二進位制資料型別有:BIT、BINARY、VARBINARY、TINYBLOB、BLOB、MEDIUMBOLB、LONGBLOB。
1.BIT型別
BIT資料型別用來儲存位欄位值,BIT(M),M表示每個值的位數,範圍1~64。若M被忽略,預設1。
例:建立表tmp12,定義BIT(4)型別的欄位b,向表中插入資料2、9、15、16。
mysql> INSERT INTO tmp12 VALUES(2),(9),(15),(16);
ERROR 1406 (22001): Data too long for column 'b' at row 4
出現錯誤,16超出了4位二進位制數的範圍。
mysql> SELECT BIN(b+0) FROM tmp12;
+----------+
| BIN(b+0) |
+----------+
| 10 |
| 1001 |
| 1111 |
+----------+
3 rows in set (0.09 sec)
mysql> SELECT b+0 FROM tmp12;
+------+
| b+0 |
+------+
| 2 |
| 9 |
| 15 |
+------+
3 rows in set (0.00 sec)
其中: b+0表示將二進位制的結果轉換為對應的數字值,BIN()函式將數字轉化為二進位制。
2.BINARY和VARBINARY
BINARY和VARBINARY類似於CHAER和VARCHAR,BINARY型別的長度是固定的,VARBINARY型別的長度是可變的且實際佔用空間為字串實際長度加一。
例:建立表tmp13,定義BINARY(3)型別欄位b和VARBINARY(3)型別的欄位vb,並向表中插入資料‘5’,比較兩個欄位的儲存空間:
mysql> CREATE TABLE tmp13(b BINARY(3),vb VARBINARY(3));
Query OK, 0 rows affected (0.34 sec)
mysql> INSERT INTO tmp13 VALUES(5,5);
Query OK, 1 row affected (0.02 sec)
mysql> SELECT length(b),length(vb) FROM tmp13;
+-----------+------------+
| length(b) | length(vb) |
+-----------+------------+
| 3 | 1 |
+-----------+------------+
1 row in set (0.00 sec)
進一步確認5在兩個欄位中不同的儲存方式:
mysql> SELECT b,vb,b='5',b='5\0\0',vb='5',vb='5\0\0' FROM tmp13;
+------+------+-------+-----------+--------+------------+
| b | vb | b='5' | b='5\0\0' | vb='5' | vb='5\0\0' |
+------+------+-------+-----------+--------+------------+
| 5 | 5 | 0 | 1 | 1 | 0 |
+------+------+-------+-----------+--------+------------+
1 row in set (0.00 sec)
b欄位不足的空間填充了‘\0’。
3.BOLB型別
BLOB型別的儲存範圍:
資料型別 | 儲存範圍 |
---|---|
TINYBLOB | 最大長度為255(28-1)位元組 |
BLOB | 最大長度為65535(216-1)位元組 |
MEDIUMBLOB | 最大長度為16777215(224-1)位元組 |
LONGBLOB | 最大長度為4294967295或4GB(232-1)位元組 |
BLOB列儲存的是二進位制字串(位元組字串);TEXT列儲存的是字元字串。BLOB列沒有字符集,並且排序和比較基於列位元組的數值;TEXT列有一個字符集,並且根據字符集對值進行排序和比較。