MYSQL快速入門(2)
前言:本篇部落格是接著MYSQL快速入門(1)
的繼續學習。
MYSQL快速入門(1):https://blog.csdn.net/hansionz/article/details/84111426
MYSQL快速入門
一.MYSQL的資料型別
1.資料型別分類
2.數值型別
2.1 BIT的使用
bit[(M)]
位欄位型別。M
表示每個值的位數,範圍從1到64
。如果M
被忽略,預設為1
。
create table p1( id int, tel bit(8));
insert into p1 values(10,10 );
select * from p1;
該sql
語句執行結果如下:
tel欄位
的值並沒有顯示,bit欄位
在顯示時,是按照ASCII碼
對應的值顯示。下圖,當插入65
時,對應的字元為A
。
如果我們有這樣的值,只存放0或1,只存在兩種狀態
,這時可以定義bit(1)
。這樣可以節省空間
。
create table p2(gender bit(1));
insert into p2 values(0);
insert into p2 values(1);
insert into p2 values(2); -- 不能插入2,因為只有1位,插入2會越界
2.2 整型型別的使用
對於上邊的幾個型別
,我們應該注意的是它們所能使用的範圍
,注意越界問題
。
crate table p3(id tinyint); -128-127
insert into p3 values(1);
insert into p3 values(128);-- 會報錯,越界插入
在MySQL
中,整型可以指定是有符號
的和無符號
的,預設是有符號
的。 可以通過UNSIGNED
來說明某個欄位是無符號
的。
create table p4(num tinyint unsigned); -- 0-255
insert into p4 values(-1);-- 越界插入
insert into p4 values(255);
其他的整型型別和TINYINT
型別的使用完全一樣,只要使用時注意範圍
即可。
2.3 UNSINGED的使用
int
的表示範圍是-2147483648 ~ 2147483647
,int unsigned
的範圍是0 ~ 4294967295
。所以我們在很多時候需要使用unsigned
來表示非負數
,比如年齡
等。然而在實際使用中,unsigned
可能會帶來一些負面的影響
。
create table p5(a int unsigned, b int unsigned);
insert into p5 values(1,2);
select a - b from p5;
-- 預料的應該是-1,但其實不然,-1減去2是正的最大值,-1(FFFFFFFF)和4294967295(FFFFFFFF)的補碼相同,將這個數按照無符號數輸出,結果是4294967295而不是-1
要獲得正確的結果,我們想要設定引數對SQL_ MODE
。
set sql_mode='NO_UNSIGNED_SUBTRACTION';
這樣結果才是我們想要的結果。
實際使用中,儘量不使用unsigned
,因為可能帶來一些意想不到的效果。另外,對於int型別
可能存放不下的資料,int unsigned
同樣可能存放不下,與其如此,還不如設計時,將int
型別提升為bigint
型別。
2.4 小數型別的使用
2.4.1 float的使用
float[(m, d)][unsigned]
:m指定顯示長度,d指定小數位數,佔用空間4個位元組。
float(4,2)
表示的範圍是-99.99 ~ 99.99
,MySQL
在儲存值時會進行四捨五入
。
create table p6(id int, sal float(4,2));
insert into p6 values(1,-99.99);
insert into p6 values(1,-99.991); -- 先進行四捨五入,然後在插入
insert into p6 values(1,99.991);
insert into p6 values(1,99.999); -- 報警告,但依然會捨棄超出部分
執行結果: show warnings 可以打印出所有的警告資訊。
如果定義的是float(4,2) unsigned
這時,因為把它指定為無符號的數
,範圍是 0 ~ 99.99
。
create table p7(id int, sal float(4,2) unsigned);
insert into p7 values(1,-0.1);-- 報警告
insert into p7 values(1,-0); -- yes
insert into p7 values(1,99.99); -- yes
打印出警告資訊:
2.4.2 decimal的使用
decimal(m, d) [unsigned]
:定點數m指定長度,d表示小數點的位數
decimal整數最大位數m為65
。支援小數最大位數d是30
。如果d被省略,預設為0
。如果m
被省略,預設 是10
。
-- float和decimal很相似,但是他們有區別,表示的精度不同,float表示的精度大約是7位
decimal(5,2) 表示的範圍是 -999.99 ~ 999.99
decimal(5,2) unsigned 表示的範圍 0 ~ 999.99
create table p8(sal1 float(10,8),sal2 decimal(10,8))
insert into t8 values(12.12345678,11.12345678);
下圖為插入記錄的結果:由此結果可以看出decimal
的精度要比float
的精度高,如果要儲存更高精度的數,推薦使用decimal
。
2.5 字串
2.5.1 char和varchar
-
char(L)
: 固定長度字串,L是可以儲存的長度
,單位為字元
,大長度值可以為255
-
varchar(L)
: 可變長度字串,L表示字元長度
,最大長度65535
個位元組
注:L是表示字元的個數,而不是位元組的個數。
# 測試char
-- char(2) 表示可以存放兩個字元,可以是字母或漢字,但是不能超過2個。最多隻能是255
create table p8(id int, name char(2));
insert into p8 values(1,'ab'); -- ab
insert into p8 values(1,'張三'); -- 張三
-- 超出最大長度,則會建表失敗
create table tt10(id int ,name char(256));
-- 測試varchar
create table p9(id int, name varchar(6)) -- 表示可以存放6個字元
insert into p9 values(100, '我愛你,中國'); -- 插入成功
2.5.2 varchar的len
varchar的len到底是多長呢?varchar(L),L代表的是字元的個數,但是總的最大位元組數是65535
。varchar
的len其實是與 編碼有關的。
varchar
長度可以指定為0到65535
之間的,但是有1 - 3
個位元組用於記錄資料大小
,所以說有效位元組數是65532
。- 當表的編碼是
utf8
時,varchar(n)
。n
大值是65532/3=21844
。(因為utf8中,一個漢字佔用3個位元組
) - 如果編碼是
gbk
,varchar(n)
。n大是65532/2=32766
(因為gbk
中,一個漢字佔用2位元組
)。
當我們以utf8編碼
建立一個varchar(21845)
的表會失敗,但是建立varchar(21844)
的表就會建立成功。
注意:我們在建立表的時候並不是只建立有一個varchar
欄位,還可能存在其他欄位,如果存在其他欄位,那麼varchar
的最大長度並不是21844
,而是要減去其他型別所佔的長度,因為mysql
規定,表中一行的記錄不能超過65535
。
上邊的例子中,varchar的最大長度應該是21844 - 4(int) = 21840
,所以第一次建表報錯,第二次建表成功。
在一些使用場景下,應該如何選擇char
和varchar
:
- 如果資料確定
長度都一樣
,就使用定長
,比如身份證,手機號,md5加密的密碼。(定長的磁碟空間比較浪費,但是效率高)
- 如果資料
長度有變化
,就使用變長
,比如名字,地址,但是你要保證長的能存的進去。(變長的磁碟空間比較節省,但是效率低)
2.6 日期和時間型別
MYSQL中常用的日期和時間型別有:
datatime
:日期時間格式為yyyy-mm-dd HH:MM:SS
,表示範圍從1000-9999
,佔用8個位元組date
:日期格式為yyyy-mm-dd
,佔用3個位元組timestamp
:時間戳,,從1970年開始的yyyy-mm-dd HH:MM:SS
格式和datetime
完全一致,佔用4位元組
create table birthday(t1 date, t2 datetime, t3 timestamp)
-- 新增資料時,時間戳自動補上當前時間
-- 更新資料,時間戳會更新成當前時間
insert into birthday(t1,t2) values('1997-3-6','1997-3-6 12:00:00')
當更新表中的資料時,時間戳會自動更新為當前的時間:
update birthday set t2 = '2008-3-6';
2.6 列舉和set型別
2.6.1 列舉型別
列舉,其實就是“單選”
型別,對應介面
或表單
中的“單選項”
的資料值。該設定只是提供了若干個選項
的值,最終在一個單元格中,實際只儲存了其中一個值
;而且,處於效率考慮,這些值實際儲存的是“數字”
,因為這些選項,每個選項值,一次對應如下數字:1,2,3,....多65535
個。列舉型別其實和C
中的列舉型別是一個概念。
enum('選項1','選項2','選項3',...);
當我們新增列舉值時,也可以直接新增編號。
2.6.2 set型別
set
型別正好和enum
相對。set就是“多選”
型別,對應於介面或表單的“多選項”
的資料值。該設定只是提供了若干個選項的值,最終在一個單元格中,可儲存了任何其中的多個值
。基於效率考慮, 這些實際儲存的是“數字”
,因為這些選項,每個選項值,一次對應如下數字:1,2,4,8,16,32,....最多64個;[偶數]
。
set('選項值1','選項值2','選項值3', ...);
當我們新增set型別的值時,也可以直接新增編號。
2.6.3 set和enum例子
有一個調查表votes
,需要調查人的喜好,比如登山,游泳,籃球,武術(多選)
。 性別為男和女(單選)
。
-- 建表
create table votes(
name varchar(32),
hobby set('登山','游泳','籃球','武術'),
gender enum('男','女')
)charset=utf8;
-- 插入幾條記錄
insert into votes values('張三', '登山,武術', '男');
-- 列舉型別可以直接插入編號
insert into votes values('李四','登山,武術',2);
insert into votes values('王五','游泳',2);
select * from votes where hobby='登山';
以下為插入結果:
- 找出所有愛好
有登山
的人
-- 這樣做查不出來
select * from votes where hobby='登山';
-- find_in_set(sub,str_list); 如果sub在str_list中,則返回下標,如果不在,返回0 str_list用逗號分隔的字串。
-- 這樣做ok
select * from votes where find_in_set('登山', hobby);
find_in_set
的用法如下:
二.表的約束
真正約束表中欄位的是資料型別
,但是資料型別約束很單一
,需要有一些額外的約束,更好的保證資料的合法性
,從業務邏輯角度保證資料的正確性
。比如有一個欄位是id,要求是唯一的。
1.空屬性
1.1 空屬性概念
空屬性存在兩個值:null(預設的)
和not null(不為空)
。 資料庫預設欄位基本都是欄位為空
,但是實際開發
時,儘可能保證欄位不為空
,因為資料為空沒辦法參與運算
。
select null; -- null
select 1+null; -- 空值沒法參加運算,運算結果依然為空
下邊為運算結果:
1.2 空屬性約束的應用
假設要建立一個班級表
,該表包含班級名
和班級所在的教室
。如果班級沒有名字
,你知道你在哪個班級
;如果教室名字
可以為空,就不知道在哪上課
。
create table class(
class_name varchar(20) not null,
class_room varchar(20) not null
)charset=utf8;
使用desc class
查看錶的結構:
當我們在插入資料,沒有給出class_name
或者class_room
時,就會報錯,因為我們已經設定約束該欄位不能為空:
insert into class values('1603','203'); -- ok
insert into class values('1604'); -- 報錯
下邊為執行結果:
2.預設值
預設值是指某一種資料會經常性的出現某個具體的值
,可以在一開始就指定好
,在需要真實資料的時候,使用者可以選擇性的使用預設值
。(可以理解為C++中的預設引數)
-- 建立一個帶有預設值約束的學生表
create table stu(
name varchar(30) not null,
age tinyint unsigned default 0,
gender char(2) default '男'
)charset=utf8;
使用desc stu
查看錶的結構:
預設值的生效:資料在插入的時候不給該欄位賦值
,就使用預設值
。
insert into stu values('張三',17,'女');
-- 年齡和性別欄位使用預設值
insert into stu values('李四');
以下為執行結果:
注:set和enum型別欄位不能設定預設值。
3.列描述
列描述:comment
,沒有實際含義,專門用來描述欄位
,會根據表建立語句儲存
,用來給程式設計師來進行理解。可以理解為C語言中的註釋資訊
建立一個person
表,給每一個欄位加上列描述:
create table person(
name varchar(20) not null comment '姓名',
age tinyint unsigned default 0 comment '年齡',
gender char(2) default '男' comment '性別'
)charset=utf8;
使用desc person
查看錶結構,可以發現看不到註釋資訊:
使用show create table person\G (加上\G可以以一種簡單的形式列印資訊)
檢視建表的資訊,才可以檢視到註釋資訊:
4.zerofill(0填充)
建立一個帶有整型欄位
的表:
create table z1(
a int(10) unsigned zerofill default NULL,
b int unsigned default 0
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
整型
是代表的4個位元組
,但是後邊的10
代表的是什麼?其實int(10)
如果沒有設定zerofill
約束這個值沒有任何意義。但是如果設定zerofill
約束,當你要插入的數位數沒有達到10位,其他位數就會被0填充
。
插入一條資料檢視結果:
insert into z1 values(1,2);
下邊為插入結果:
a
的值由原來的1變成0000000001
,這就是zerofill屬性
的作用,如果寬度小於設定的寬度(這裡設定的是 10)
,自動填充0
。要注意的是,這只是後顯示的結果,在MySQL中實際儲存的還是1。
使用內建函式hex()
將a的值轉為十六進位制:
由結果可以看出資料庫內部儲存的還是1
,0000000001
只是設定了zerofill屬性後的一種格式化輸出
而已。
5.主鍵約束
主鍵primary key:
用來唯一的約束該欄位
裡面的資料,不能重複、不能為空、主鍵所在的列是整數型別
。一張表中多只能有一個主鍵
,建立表的時候直接在欄位上指定主鍵
。
5.1 單個欄位的主鍵
- 建立一個帶有
主鍵id
的表
create table z2(
id int unsigned primary key comment '學號', -- id一個欄位加主鍵約束
name varchar(20) not null comment '姓名'
)charset=utf8;
- 使用
desc z2
檢視該表的結構
Key中的PRI代表的是主鍵。
5.2 多個欄位的主鍵(複合主鍵)
建立表的時候,在所有欄位
之後,使用primary key(主鍵欄位列表)
來建立主鍵,如果有多個欄位作為主鍵,可以使用複合主鍵
。
- 建立一張以
多個欄位為主鍵
的表
create table z3(
id int unsigned comment '學號',
course char(10) comment '課程程式碼',
score tinyint unsigned default 60 comment '成績',
primary key(id, course) -- id和course為複合主鍵,複合主鍵一定是在所有欄位後宣告的
)charset=utf8;
- 使用
desc z3
檢視該表的結構
可以看出id和course
為複合主鍵。
- 當一個表建好後,也可以追加主鍵約束
-- 語法:
alter table 表名 add primary key(欄位列表)
-- 建立一個沒有主鍵的表
create table z4(
id int,
name varchar(20)
);
-- 增加主鍵約束
alter table z4 add primary key(id);
使用desc
查看錶的結構,可以看到主鍵追加完成:
5.3 主鍵約束
主鍵對應的欄位中不能重複
,一旦重複,操作失敗。
例如:在z4中插入兩個記錄:
insert into z4 values(1,'a'); -- 插入成功
insert into z4 values(1,'b'); -- 插入失敗,主鍵不唯一
下邊為插入結果:
5.4 刪除主鍵
語法:alter table 表名 drop primary key;
例如:刪除表z4中的主鍵:
alter table z4 drop primary key;
desc
查看錶結構,發現主鍵被刪除:
6.自增長
6.1 自增長概念
自增長auto_increment:
當對應的欄位,沒有給值,會自動的被系統觸發
,系統會從當前欄位中已經有的值進行+1操作
, 得到一個新的不同的值。通常和主鍵搭配使用,作為邏輯主鍵。
6.2 自增長的特點
- 任何一個欄位要做自增長,前提是本身是一個
索引(key一欄有值)
- 自增長
欄位必須是整數
- 一張表多
只能有一個自增長
例如:建立一個帶有自增長約束的表,並進行插入操作:
create table z5(
id int unsigned primary key auto_increment, -- 邏輯主鍵
name varchar(10) not null default ''
);
-- 插入兩條記錄
insert into tt21(name) values('a');
insert into tt21(name) values('b');
使用select * from z5
檢視插入結果:
7.唯一鍵(unique)
一張表中有往往有很多欄位需要唯一性
,資料不能重複
,但是一張表中只能有一個主鍵
。唯一鍵就可以解決表中有多個欄位需要唯一性約束
的問題。唯一鍵的本質和主鍵差不多,唯一鍵允許為空,而且可以多個為空,空欄位不做唯一性比較。
- 建立一個帶有唯一性約束的表,並插入一些資料
create table z6(
id int unique,
name varchar(20) not null
);
-- 插入幾條記錄
insert into z6(id, name) values('01', 'a'); -- 插入成功
insert into z6(id, name) values('01', 'b'); -- id不唯一
insert into z6(id, name) values(null, 'c'); -- 可以插入null
- 使用
select * from z6
檢視插入結果
注:在MYSQL
中的各類語句一般使用大寫
,在本篇博文中,由於大寫寫起來比較難看懂
,所以就採用小寫
。