1. 程式人生 > >Mysql學習之路06-外來鍵

Mysql學習之路06-外來鍵

外來鍵
外來鍵的作用,主要有兩個:
一個是讓資料庫自己通過外來鍵來保證資料的完整性和一致性
對子表的約束:子表進行寫操作的時候,如果對應的外來鍵欄位在父表找不到對應的匹配,那麼操作失敗(約束子表資料操作)
對父表的約束:父表資料進行(刪和改:都必須涉及到主鍵本身),如果對應的主鍵在子表中已經被資料所引用,那麼就不允許操作
一個就是能夠增加ER圖的可讀性
一張表可以有多個外來鍵
增加外來鍵
alter table 表名
add [constraint 外來鍵名] foreign key [id] (index_col_name, …)
references 表名 (index_col_name, …)
刪除外來鍵:外來鍵不可修改;
alter table 表名 drop foreign key(外來鍵名);

外來鍵條件:
1,外來鍵要存在:首先保證表的儲存引擎是innodb,如果不是innodb儲存引擎,外來鍵可以建立,但是沒有約束效果
2,外來鍵欄位的欄位型別必須與父表的主鍵型別完全一致
3,增加外來鍵的欄位(資料已經存在),必須保證資料與父表主鍵要求對應

外來鍵約束:通過對外來鍵的需求,進行定製操作,都是對父表的約束
district:嚴格模式(預設的),父表不能刪除或者更新一個已經被子表資料引用的記錄
cascade:級聯模式:父表的操作,對應子表關聯的資料也跟著操作
set null:置空模式:父表的操作之後,子表對應的資料(外來鍵欄位)被置空
語法:foreign key(外來鍵欄位)references 父表(主鍵欄位) on delete set null update cascade;

主鍵和外來鍵是相對於整個資料庫來說的,總體來說就是要實現資料庫的實體完整性、參照完整性等完整性的約束。並滿足資料庫規範化的要求 1NF、2NF…
對於一個表定義了一個主鍵,對於該表可以為通過該鍵唯一地表示表中的每一記錄。外來鍵是相對於表中的一個列給它的一個約束,一般是另一個表中的主鍵,該列的值必須在另一個表中出現。
由此可見,外來鍵表示了兩個關係之間的聯絡。以另一個關係的外來鍵作主關鍵字的表被稱為主表,具有此外來鍵的表被稱為主表的從表。外來鍵又稱作外關鍵字。
外來鍵的作用:
保持資料一致性,完整性,主要目的是控制儲存在外來鍵表中的資料。 使兩張表形成關聯,外來鍵只能引用外表中的列的值!
恩, 好象不缺少一些關係資料庫的基礎知識.
簡單的說, 在關係型資料庫中的每一個表都具備這樣的特點, 在同一個表中沒有完全一致的兩行資料, 當一行資料可以有少數幾個屬性確定的話,這幾個屬性就可以成為主鍵, 設立了表的主鍵之後,資料庫系統會為主鍵的列建立索引和制約, 利用主鍵進行檢索的速度是最快的.
如果有兩個表AB, 他們之間存在著某種對應關係,這種關係可以是A中一行記錄對應於B中的一行記錄,也可以是A的一行記錄對應於B的多行記錄,還可以是A的多行對應於B的多行,在關係型資料庫中, 這種對應關係也要做成關係表,下面就一對一, 一對多, 多對多幾種情況來說明一下關係表
一對一
表A(學號, 姓名)
表B(學號, 學習成績)
表A是一份學生名單, 學號是主鍵
表B是一份成績單, 學號也是主鍵,這樣兩個表就是一對一的關係, 反映出這一關係的是學號, 如果把表A做為主表的話, 表B的學號就是外來鍵了

一對多
表A(班級, 人數)
表B(學號, 姓名)
表A是一份班級列表, 表B是一分學生名單,每個學生都屬於某一個班級, 而一個班級可以有很多學生
為了表示這樣的關係, 可以做一個關係表C(學號,班級) 其中,學號是主鍵, 這就保證了一對多的關係, 而學號和班級, 都是外來鍵, 由於B,C

多對多
表A(課程, 學分)
表B(學號, 姓名)
表A是一份課程表
表B是份名單, 一個學生可以選多門課程,一門課程中也可以有很多學生, 為了反映這樣的關係建立表C(課程,學號)其中課程和學號都是主鍵,這就保證了多對多的關係, 同時他們也是外來鍵

作為外來鍵的屬性反映了主表中的某些屬性, 因此其型別要和主表的對應屬性一致才行
建立了外來鍵之後會產生一致性的制約, 比如說, 在一對多的例子中, 不允許在關係表中出現主表中沒有的學號或者是班級,
另外,對外來鍵的更新和刪除, 也就有了下面兩種制約
- 級聯, 當刪除了主表的主鍵之後, 同時也刪除關係表中的外來鍵, 比如,刪除了一對多的例子中刪除了班級, 系統會自動刪除關係表C中含有該班級的所有記錄
- 制約, 只有當關系表中沒有與該主鍵對應的外來鍵時才允許刪除該主鍵,再比如, 在一對多的例子中, 想刪除某一班級的話,就必須先刪除關係表C中所有含該班級的記錄

外來鍵的設立可以保證資料的對應關係避免因為錯誤操作而遭到破壞,同時, 外來鍵也可以提示系統事先建立索引和結合操作的執行計劃,從而提高結合計算的效率
  例如:
  a b 兩個表
  a表中存有客戶號,客戶名稱
  b表中存有每訂個客戶的單
  有了外來鍵後
  你只能在確信b 表中沒有客戶x的訂單後,才可以在a表中刪除客戶x
  建立外來鍵的前提: 本表的列必須與外來鍵型別相同(外來鍵必須是外表主鍵)。
  指定主鍵關鍵字: foreign key(列名)
  引用外來鍵關鍵字: references <外來鍵表名>(外來鍵列名)(被參考的表)
  事件觸發限制: on delete和on update ,可設引數cascade(跟隨外來鍵改動), restrict(限制外表中的外來鍵改動),set Null(設空值),set Default(設預設值),[預設]no action
  例如:
  outTable表 主鍵 id型別 int
  建立含有外來鍵的表:
  create table temp(
  id int,
  name char(20),
  foreign key(id) references outTable(id) on delete cascade on update cascade);
  說明:把id列 設為外來鍵 參照外表outTable的id列 當外來鍵的值刪除 本表中對應的列篩除 當外來鍵的值改變 本表中對應的列值改變。
  建鍵幾個原則:
  1、 為關聯欄位建立外來鍵。
  2、 所有的鍵都必須唯一。
  3、避免使用複合鍵。
4、外來鍵總是關聯唯一的鍵欄位。
在關係中所有表中具有相同含義的欄位作為公共部分來連線不同表中的記錄。外來鍵可以是一對一的,一個表的記錄只能與另一個表的一條記錄連線,或者是一 對多的,一個表的記錄與另一個表的多條記錄連線。
MySQL中“鍵”和“索引”的定義相同, 所以外來鍵和主鍵一樣也是索引的一種。不同的是MySQL會自動為所有表的主鍵進行索引,但是外來鍵欄位必須由使用者進行明確的索引。這和一些封建思想比較沉重的家庭是一樣的,外來的孩子(兒媳婦,倒插門女婿)一般都是不受重視的。
表間一對一關係示例:
有兩張表,第一張表是記錄公司有多少人,都有誰,也就是員工編號及員工姓名這些基本表。另一張表記錄每個月發給使用者多少工資,所謂工資表是也。
但是工資表裡面不能以員工姓名為主鍵,同樣要通過員工id,因為員工的姓名是可能重複的啊。部門經理叫張三,小弟也叫張三,那這倆張三的工資能一樣嗎?並且員工表裡面的每個人都有工資,否則誰也不給你幹活,且一個人只能有一份工資,否則老闆也不同意了。所以員工表和工資表是通過員工id進行關聯的一 對一關係。
/建立員工表/
create table employees (
id int(5) not null auto_increment ,
name varchar(8) not null,
primary key (id)
)
type=innodb;
/*
建立工資表
*/
create table payroll(
id int(5) not null,
emp_id int(5) not null,
name varchar(8) not null,
payroll float(4,2) not null,
primary key(id),
index emp_id (emp_id),
foreign key (emp_id) references employees (id)
)
type = innodb;
參照完整性:
當外來鍵與另一個表的欄位有關係,而且這種關係是惟一時,這個系統就稱為處於參照完整性的狀態。也就是說,如果一個欄位在所有的表中只出現一次,而且每個表的這個欄位的變化都會影響其他表,這就是存在參照完整性。
術語理解上可能不太方便,其實就是說要在有外來鍵的表中保持所有資料的一致性。比如說“張三”離職了,在員工表裡面肯定沒有這個人了,可是如果在工資表裡面還存在這個孩子,那麼老大就會很生氣的。
MySQL的外來鍵只能在InnoDB表中使用:
MySQL對此一直持觀望態度,它允許使用外來鍵,但是為了完整性檢驗的目的,在除了InnoDB表型別之外的所有表型別中都忽略了這個功能。這可能有些怪異,實際上卻非常正常:對於資料庫的所有外來鍵的每次插入、更新和刪除後,進行完整性檢查是一個耗費時間和資源的過程,它可能影響效能,特別是當處理 複雜的或者是纏繞的連線樹時。因而,使用者可以在表的基礎上,選擇適合於特定需求的最好結合。。
所以,如果需要更好的效能,並且不需要完整性檢查,可以選擇使用MyISAM表型別,如果想要在MySQL中根據參照完整性來建立表並且希望在此基 礎上保持良好的效能,最好選擇表結構為innoDB型別。
MySQL建立外來鍵語法:
建立外來鍵的語法是這樣的:FOREIGN KEY (當前表的欄位名)… REFERENCES參照表 (參照表的欄位名)
foreign key (emp_id) references employees (id);的意思就是說當前表的emp_id欄位是以employees的id欄位為外來鍵的。
注意事項:
關係中的所有表必須是innoDB表,在非InnoDB表中,MySQL將會忽略FOREIGN KEY…REFERENCES修飾符。
用於外來鍵關係的欄位必須在所有的參照表中進行明確地索引,InnoDB不能自動地建立索引。
在外來鍵關係中,欄位的資料型別必須相似,這對於大小和符號都必須匹配的整數型別尤其重要。
即使表存在外來鍵約束,MySQL還允許我們刪除表,並且不會產生錯誤(即使這樣做可能會破壞更早建立的外來鍵)
刪除外來鍵方法:
long long ago,人們只能通過刪除表來刪除外來鍵。不過現在MySQL(在4.0.13及更高版本中)提供了一種從表中刪除外來鍵比較緩和的方法,緩和與否不太清楚,但是至少不再那麼無恥。
ALTER TABLE table-name DROP FOREIGN KEY key-id;
這裡有一個概念,這個外來鍵的id是啥玩意?我們可以通過SHOW CREATE TABLE 命令來獲得key-id的值。日後我們詳細討論這些內容,大家可以自行演示。
/*
顯示建表結構語句,key-id為payroll_ibfk_1
*/
show create table payroll \G
/*

   Table: payroll

Create Table: CREATE TABLE payroll (
id int(5) NOT NULL,
emp_id int(5) NOT NULL,
name varchar(8) NOT NULL,
payroll float(4,2) NOT NULL,
PRIMARY KEY (id),
KEY emp_id (emp_id),
CONSTRAINT payroll_ibfk_1 FOREIGN KEY (emp_id) REFERENCES employees (id)
) ENGINE=InnoDB DEFAULT CHARSET=latin1
1 row in set (0.00 sec)
*/
自動鍵更新和刪除:
外來鍵可以保證新插入的記錄的完整性。但是,如果在REFERENCES從句中從已命名的表刪除記錄會怎樣?在使用同樣的值作為外來鍵的輔助表中會發生什麼?
很明顯,那些記錄也應該被刪除,否則在資料庫中就會有很多無意義的孤立記錄。MySQL可能通過向FOREIGN KEY…REFERENCES修飾符新增一個ON DELETE或ON UPDATE子句簡化任務,它告訴了資料庫在這種情況如何處理孤立任務。
請注意,通過 ON UPDATE 和ON DELETE規則,設定MySQL能夠實現自動操作時,如果鍵的關係沒有設定好,可能會導致嚴重的資料破壞。例如,如果一系列的表通過外來鍵關係和ON DELETE CASCADE規則連線時,任意一個主表的變化都會導致甚至只和原始刪除有一些將要聯絡的記錄在沒有警告的情況下被刪除。所以,我們在操作之前還是要檢查這些規則的,操作之後還要再次檢查。

在MySQL 3.23.44版本後,InnoDB引擎型別的表支援了外來鍵約束。
外來鍵的使用條件:
1.兩個表必須是InnoDB表,MyISAM表暫時不支援外來鍵(據說以後的版本有可能支援,但至少目前不支援);
2.外來鍵列必須建立了索引,MySQL 4.1.2以後的版本在建立外來鍵時會自動建立索引,但如果在較早的版本則需要顯示建立;
3.外來鍵關係的兩個表的列必須是資料型別相似,也就是可以相互轉換型別的列,比如int和tinyint可以,而int和char則不可以;
外來鍵的好處:可以使得兩張表關聯,保證資料的一致性和實現一些級聯操作;
外來鍵的定義語法:
[CONSTRAINT symbol] FOREIGN KEY [id] (index_col_name, …)
REFERENCES tbl_name (index_col_name, …)
[ON DELETE {RESTRICT | CASCADE | SET NULL | NO ACTION | SET DEFAULT}]
[ON UPDATE {RESTRICT | CASCADE | SET NULL | NO ACTION | SET DEFAULT}]
該語法可以在 CREATE TABLE 和 ALTER TABLE 時使用,如果不指定CONSTRAINT symbol,MYSQL會自動生成一個名字。
ON DELETE、ON UPDATE表示事件觸發限制,可設引數:
RESTRICT(限制外表中的外來鍵改動)
CASCADE(跟隨外來鍵改動)
SET NULL(設空值)
SET DEFAULT(設預設值)
NO ACTION(無動作,預設的)