學習筆記2021 12 10cont
2021.12.10
約束
約束的概述:
資料完整性(Data Integrity)是指資料的精確性(Accuracy)和可靠性(Reliability)。它是防止資料庫中存在不符合語義規定的資料和防止因錯誤資訊的輸入輸出造成無效操作或錯誤資訊而提出的。
為了保證資料的完整性,SQL規範以約束的方式對表資料進行額外的條件限制。從以下四個方面考慮:
實體完整性(Entity Integrity)
:例如,同一個表中,不能存在兩條完全相同無法區分的記錄域完整性(Domain Integrity)
:例如:年齡範圍0-120,性別範圍“男/女”引用完整性(Referential Integrity)
:例如:員工所在部門,在部門表中要能找到這個部門使用者自定義完整性(User-defined Integrity)
:例如:使用者名稱唯一、密碼不能為空等,本部門經理的工資不得高於本部門職工的平均工資的5倍。
約束是表級的強制規定。對錶中欄位的限制!!
約束的分類
- 根據約束資料列的限制,約束可分為:
- 單列約束:每個約束只約束一列
- 多列約束:每個約束可約束多列資料
- 根據約束的作用範圍,約束可分為:
- 列級約束:只能作用在一個列上,將跟在列的定義後面定義
- 表級約束:可以作用在多個列上,不與列一起,而是單獨定義,在表中所有欄位宣告完後再在後面宣告。
位置 支援的約束型別 是否可以起約束名 列級約束: 列的後面 語法都支援,但外來鍵沒有效果 不可以 表級約束: 所有列的下面 預設和非空不支援,其他支援 可以(主鍵沒有效果)
- 根據約束起的作用,約束可分為:
- NOT NULL 非空約束,規定某個欄位不能為空
- UNIQUE 唯一約束,規定某個欄位在整個表中是唯一的
- PRIMARY KEY 主鍵(非空且唯一)約束
- FOREIGN KEY 外來鍵約束
- CHECK 檢查約束
- DEFAULT 預設值約束
如何新增約束
可以在建立表時規定約束(通過 CREATE TABLE 語句),或者在表建立之後通過 ALTER TABLE 語句規定約束。包括新增和刪除約束。
非空約束
檢視已建立表的約束的方法:
SELECT * FROM information_schema.`TABLE_CONSTRAINTS` WHERE table_name = 'employees';
作用:限定某個欄位的值不能夠為空
關鍵字 not nul
-
預設,所有的型別的值都可以是NULL,包括INT、FLOAT等資料型別
-
非空約束只能出現在表物件的列上,只能某個列單獨限定非空,不能組合非空。即非空約束屬於是列級約束。
-
一個表可以有很多列都分別限定了非空
-
空字串''不等於NULL,0也不等於NULL
具體示例:
# 建立表時新增約束
CREATE TABLE test1(
id INT NOT NULL,
last_name VARCHAR(15) NOT NULL,
email VARCHAR(25),
salary DECIMAL(10,2)
);
此時新增具體物件的時候在對應欄位下面如果不賦值或者賦值為null就都會報錯了。包括修改也是收到限制的。
刪除約束
ALTER TABLE test1
MODIFY id INT NULL;
注意對應的如果要修改約束也是一樣的語句,就是modify後面的具體內容不同而已。
唯一性約束
作用:用來限制某個欄位的值不能重複
關鍵字:unique。
特點
- 同一個表可以有多個唯一約束。
- 唯一約束可以是某一個列的值唯一,也可以多個列組合的值唯一。
- 唯一性約束允許列值為空。而且可以多次新增NULL值,即NULL可以不唯一。
- 在建立唯一約束的時候,如果不給唯一約束命名,就預設和列名相同。
- MySQL會給唯一約束的列上預設建立一個唯一索引。
新增唯一約束
(1)建表時
create table 表名稱(
欄位名 資料型別,
欄位名 資料型別 unique,
欄位名 資料型別 unique key,
欄位名 資料型別
);
create table 表名稱(
欄位名 資料型別,
欄位名 資料型別,
欄位名 資料型別,
[constraint 約束名] unique key(欄位名)
);
舉例:
CREATE TABLE test2
(
id INT UNIQUE, #此時即為列級約束
last_name VARCHAR(15),
email VARCHAR(25) ,
salary DECIMAL(10,2),
#表級約束
CONSTRAINT uni_test UNIQUE(email)
);
上面即是通過兩種不同的方法實現了對欄位的唯一性約束。
關於複合唯一約束
create table 表名稱(
欄位名 資料型別,
欄位名 資料型別,
欄位名 資料型別,
unique key(欄位列表) #欄位列表中寫的是多個欄位名,多個欄位名用逗號分隔,表示那麼是複合唯一,即多個欄位的組合是唯一的
);
CREATE TABLE uu
(
id INT,
`name` VARCHAR(15),
`psd` VARCHAR(25),
CONSTRAINT u_name_psd UNIQUE(`name`,`psd`)
);
注意此時複合的約束只有整體一樣才會排斥,只有其中一個成員不一樣的話是不會報錯的。
刪除唯一約束
- 新增唯一性約束的列上也會自動建立唯一索引。
- 刪除唯一約束只能通過刪除唯一索引的方式刪除。
- 刪除時需要指定唯一索引名,唯一索引名就和唯一約束名一樣。
- 如果建立唯一約束時未指定名稱,如果是單列,就預設和列名相同;如果是組合列,那麼預設和()中排在第一個的列名相同。也可以自定義唯一性約束名。
SELECT * FROM information_schema.table_constraints WHERE table_name = '表名'; #檢視都有哪些約束
ALTER TABLE uu DROP INDEX u_name_psd;
此時即實現了對上面的複合約束的刪除。
注意:可以通過
show index from 表名稱;
查看錶的索引
主鍵約束
作用:用來表示表中的一行記錄
primary key
特點
- 主鍵約束相當於唯一約束+非空約束的組合,主鍵約束列不允許重複,也不允許出現空值。
-
一個表最多隻能有一個主鍵約束,建立主鍵約束可以在列級別建立,也可以在表級別上建立。
-
主鍵約束對應著表中的一列或者多列(複合主鍵)
-
如果是多列組合的複合主鍵約束,那麼這些列都不允許為空值,並且組合的值不允許重複。
-
MySQL的主鍵名總是PRIMARY,就算自己命名了主鍵約束名也沒用。
-
當建立主鍵約束時,系統預設會在所在的列或列組合上建立對應的主鍵索引(能夠根據主鍵查詢的,就根據主鍵查詢,效率更高)。如果刪除主鍵約束了,主鍵約束對應的索引就自動刪除了。
-
需要注意的一點是,不要修改主鍵欄位的值。因為主鍵是資料記錄的唯一標識,如果修改了主鍵的值,就有可能會破壞資料的完整性。
新增主鍵約束
(1)建表時指定主鍵約束
create table 表名稱( 欄位名 資料型別 primary key, #列級模式 欄位名 資料型別, 欄位名 資料型別 );create table 表名稱( 欄位名 資料型別, 欄位名 資料型別, 欄位名 資料型別, [constraint 約束名] primary key(欄位名) #表級模式);
舉例:
CREATE TABLE test3( id INT PRIMARY KEY, #此時即為列級約束 last_name VARCHAR(15), email VARCHAR(25) , salary DECIMAL(10,2) #表級約束 #CONSTRAINT p_test UNIQUE(id));
#演示一個表建立兩個主鍵約束create table temp( id int primary key, name varchar(20) primary key);ERROR 1068 (42000): Multiple(多重的) primary key defined(定義)
(2)建表後增加主鍵約束
ALTER TABLE 表名稱 ADD PRIMARY KEY(欄位列表); #欄位列表可以是一個欄位,也可以是多個欄位,如果是多個欄位的話,是複合主鍵
ALTER TABLE student ADD PRIMARY KEY (sid);
ALTER TABLE emp5 ADD PRIMARY KEY(NAME,pwd);
關於複合主鍵
create table 表名稱( 欄位名 資料型別, 欄位名 資料型別, 欄位名 資料型別, primary key(欄位名1,欄位名2) #表示欄位1和欄位2的組合是唯一的,也可以有更多個欄位);
CREATE TABLE uu2( id INT, `name` VARCHAR(15), `psd` VARCHAR(25), PRIMARY KEY(`name`,`psd`));
- 再舉例
CREATE TABLE emp6(id INT NOT NULL,NAME VARCHAR(20),pwd VARCHAR(15),CONSTRAINT emp7_pk PRIMARY KEY(NAME,pwd));
刪除主鍵約束
alter table 表名稱 drop primary key;
舉例:
ALTER TABLE uu2DROP PRIMARY KEY;
說明:刪除主鍵約束,不需要指定主鍵名,因為一個表只有一個主鍵,刪除主鍵約束後,非空還存在。
但在實際開發中,一般不會去刪除主鍵約束,知道有這麼一個東西就可以了。
自增列
某個欄位的值自增
auto_increment
特點
(1)一個表最多隻能有一個自增長列
(2)當需要產生唯一識別符號或順序值時,可設定自增長
(3)自增長列約束的列必須是鍵列(主鍵列,唯一鍵列)
(4)自增約束的列的資料型別必須是整數型別
(5)如果自增列指定了 0 和 null,會在當前最大值的基礎上自增;如果自增列手動指定了具體值,直接賦值為具體值。
錯誤演示:
create table employee( eid int auto_increment, ename varchar(20));# ERROR 1075 (42000): Incorrect table definition; there can be only one auto column and it must be defined as a key 必須順在主鍵約束後面
create table employee( eid int primary key, ename varchar(20) unique key auto_increment);# ERROR 1063 (42000): Incorrect column specifier for column 'ename' 因為ename不是整數型別
增加自增約束
(1)建表時
create table 表名稱( 欄位名 資料型別 primary key auto_increment, 欄位名 資料型別 unique key not null, 欄位名 資料型別 unique key, 欄位名 資料型別 not null default 預設值, );create table 表名稱( 欄位名 資料型別 default 預設值 , 欄位名 資料型別 unique key auto_increment, 欄位名 資料型別 not null default 預設值,, primary key(欄位名));
create table test7( id int primary key auto_increment, last_name varchar(20));
此時建立成功後按照這樣的模式去呼叫,對應的欄位就會自動增加,只要賦值另一個欄位就可以了。
所以開發中這麼設定過後就不要給主鍵欄位去賦值了。
(2)建表後
alter table 表名稱 modify 欄位名 資料型別 auto_increment;
例如:
create table employee( eid int primary key , ename varchar(20));
alter table employee modify eid int auto_increment;
刪除自增約束
#alter table 表名稱 modify 欄位名 資料型別 auto_increment;#給這個欄位增加自增約束alter table 表名稱 modify 欄位名 資料型別; #去掉auto_increment相當於刪除
alter table employee modify eid int;
MySQL 8.0新特性:自增變數的持久化
這裡就略了,後面用到再來了解。
外來鍵約束
限定某個表的某個欄位的引用完整性。即從表中資料時候的值,必須是主表中已經存在的值。
比如:員工表的員工所在部門的選擇,必須在部門表能找到對應的部分。
FOREIGN KEY
主表和從表的概念
主表(父表):被引用的表,被參考的表
從表(子表):引用別人的表,參考別人的表
例如:員工表的員工所在部門這個欄位的值要參考部門表:部門表是主表,員工表是從表。
例如:學生表、課程表、選課表:選課表的學生和課程要分別參考學生表和課程表,學生表和課程表是主表,選課表是從表。
特點
(1)從表的外來鍵列,必須引用/參考主表的主鍵或唯一約束的列
為什麼?因為被依賴/被參考的值必須是唯一的
(2)在建立外來鍵約束時,如果不給外來鍵約束命名,預設名不是列名,而是自動產生一個外來鍵名(例如 student_ibfk_1;),也可以指定外來鍵約束名。
(3)建立(CREATE)表時就指定外來鍵約束的話,先建立主表,再建立從表
(4)刪表時,先刪從表(或先刪除外來鍵約束),再刪除主表
(5)當主表的記錄被從表參照時,主表的記錄將不允許刪除,如果要刪除資料,需要先刪除從表中依賴該記錄的資料,然後才可以刪除主表的資料
(6)在“從表”中指定外來鍵約束,並且一個表可以建立多個外來鍵約束
(7)從表的外來鍵列與主表被參照的列名字可以不相同,但是資料型別必須一樣,邏輯意義一致。如果型別不一樣,建立子表時,就會出現錯誤“ERROR 1005 (HY000): Can't create table'database.tablename'(errno: 150)”。
例如:都是表示部門編號,都是int型別。
(8)當建立外來鍵約束時,系統預設會在所在的列上建立對應的普通索引。但是索引名是外來鍵的約束名。(根據外來鍵查詢效率很高)
(9)刪除外來鍵約束後,必須手動
刪除對應的索引
新增外來鍵約束
(1)建表時
create table 主表名稱( 欄位1 資料型別 primary key, 欄位2 資料型別);create table 從表名稱( 欄位1 資料型別 primary key, 欄位2 資料型別, [CONSTRAINT <外來鍵約束名稱>] FOREIGN KEY(從表的某個欄位) references 主表名(被參考欄位));#(從表的某個欄位)的資料型別必須與主表名(被參考欄位)的資料型別一致,邏輯意義也一樣#(從表的某個欄位)的欄位名可以與主表名(被參考欄位)的欄位名一樣,也可以不一樣-- FOREIGN KEY: 在表級指定子表中的列-- REFERENCES: 標示在父表中的列
#建立主表CREATE TABLE dept1( d_id INT PRIMARY KEY, d_name VARCHAR(15));#建立從表CREATE TABLE emp1( e_id INT, e_name VARCHAR(15), department_id INT, #表級約束FOREIGN KEY (department_id) REFERENCES dept1(d_id));
(2)建表後
一直認為這種情況是很少見的,知道可以建表後再修改這個東西就可以了。
約束等級
-
Cascade方式
:在父表上update/delete記錄時,同步update/delete掉子表的匹配記錄 -
Set null方式
:在父表上update/delete記錄時,將子表上匹配記錄的列設為null,但是要注意子表的外來鍵列不能為not null -
No action方式
:如果子表中有匹配的記錄,則不允許對父表對應候選鍵進行update/delete操作 ,也即是預設的方式。 -
Restrict方式
:同no action, 都是立即檢查外來鍵約束 -
Set default方式
(在視覺化工具SQLyog中可能顯示空白):父表有變更時,子表將外來鍵列設定成一個預設的值,但Innodb不能識別
如果沒有指定等級,就相當於Restrict方式。
對於外來鍵約束,最好是採用: 更新時 CASCADE ON 刪除時 RESTRICT
的方式。
具體的只要熟悉下格式就可以了,理論都是很好理解的。
刪除外來鍵約束
(1)第一步先檢視約束名和刪除外來鍵約束SELECT * FROM information_schema.table_constraints WHERE table_name = '表名稱';#檢視某個表的約束名ALTER TABLE 從表名 DROP FOREIGN KEY 外來鍵約束名;(2)第二步檢視索引名和刪除索引。(注意,只能手動刪除)SHOW INDEX FROM 表名稱; #檢視某個表的索引名ALTER TABLE 從表名 DROP INDEX 索引名;
理解就是注意標明刪除的外來鍵約束名並且一定記著要刪除索引名。
- 剩下的還有一些適用場景和開發規範,當涉及到更多的操作的時候再去參考。
check約束
作用
檢查某個欄位的值是否符號xx要求,一般指的是值的範圍。非空約束之類的就可以理解成check約束的一種型別了。
CHECK
MySQL 8.0中可以使用check約束了。
create table employee( eid int primary key, ename varchar(5), gender char check ('男' or '女'));
insert into employee values(1,'張三','妖');
DEFAULT約束
作用
給某個欄位/某列指定預設值,一旦設定預設值,在插入資料時,如果此欄位沒有顯式賦值,則賦值為預設值。
DEFAULT
(1)建表時
create table 表名稱( 欄位名 資料型別 primary key, 欄位名 資料型別 unique key not null, 欄位名 資料型別 unique key, 欄位名 資料型別 not null default 預設值, );create table 表名稱( 欄位名 資料型別 default 預設值 , 欄位名 資料型別 not null default 預設值, 欄位名 資料型別 not null default 預設值, primary key(欄位名), unique key(欄位名));說明:預設值約束一般不在唯一鍵和主鍵列上加
create table employee( eid int primary key, ename varchar(20) not null, gender char default '男', tel char(11) not null default '' #預設是空字串);
(2)建表後
alter table 表名稱 modify 欄位名 資料型別 default 預設值;#如果這個欄位原來有非空約束,你還保留非空約束,那麼在加預設值約束時,還得保留非空約束,否則非空約束就被刪除了#同理,在給某個欄位加非空約束也一樣,如果這個欄位原來有預設值約束,你想保留,也要在modify語句中保留預設值約束,否則就刪除了alter table 表名稱 modify 欄位名 資料型別 default 預設值 not null;
create table employee( eid int primary key, ename varchar(20), gender char, tel char(11) not null);
alter table employee modify gender char default '男'; #給gender欄位增加預設值約束alter table employee modify tel char(11) default ''; #給tel欄位增加預設值約束
刪除預設值約束
alter table 表名稱 modify 欄位名 資料型別 ;#刪除預設值約束,也不保留非空約束alter table 表名稱 modify 欄位名 資料型別 not null; #刪除預設值約束,保留非空約束
常見的面試題:
面試1、為什麼建表時,加 not null default '' 或 default 0
答:不想讓表中出現null值。
面試2、為什麼不想要 null 的值
答:(1)不好比較。null是一種特殊值,比較時只能用專門的is null 和 is not null來比較。碰到運算子,通常返回null。
(2)效率不高。影響提高索引效果。因此,我們往往在建表時 not null default '' 或 default 0
面試3、帶AUTO_INCREMENT約束的欄位值是從1開始的嗎?
在MySQL中,預設AUTO_INCREMENT的初始值是1,每新增一條記錄,欄位值自動加1。設定自增屬性(AUTO_INCREMENT)的時候,還可以指定第一條插入記錄的自增欄位的值,這樣新插入的記錄的自增欄位值從初始值開始遞增,如在表中插入第一條記錄,同時指定id值為5,則以後插入的記錄的id值就會從6開始往上增加。新增主鍵約束時,往往需要設定欄位自動增加屬性。
面試4、並不是每個表都可以任意選擇儲存引擎?
外來鍵約束(FOREIGN KEY)不能跨引擎使用。
MySQL支援多種儲存引擎,每一個表都可以指定一個不同的儲存引擎,需要注意的是:外來鍵約束是用來保證資料的參照完整性的,如果表之間需要關聯外來鍵,卻指定了不同的儲存引擎,那麼這些表之間是不能建立外來鍵約束的。所以說,儲存引擎的選擇也不完全是隨意的。