1. 程式人生 > 實用技巧 >MySQL 資料完整性

MySQL 資料完整性

資料庫實驗回顧

  1. 實體完整性

    實體完整性即主碼的屬性不能為空。而主碼就可保證元組是不重複的,即主碼值是不能重複的。

  2. 參照完整性

    參照完整性保證外碼的值要麼是被參照關係中的主碼值,要麼取空值。

  3. 使用者自定義完整性

    可以按系統的需求設計各種自定義的完整性檢查。

一、實體完整性

1、主鍵約束

主鍵(promary key)用於唯一的標識表中的某一條記錄,在兩個表的關係中,主鍵用來在一個表中引用來自另一個表中的特定記錄。一個表的主鍵可以由多個關鍵字共同組成,並且主鍵的列不能包含空值。主鍵的值能唯一標識表中的每一行,這就好比所有人都有身份證,每個人的身份證號是不同的,能唯一標識每一個人。

新增主鍵

ALTER TABLE 表名 ADD PRIMARY KEY(列名);

設定主鍵

ALTER TABLE orders ADD PRIMARY KEY(列名);

在建立表的時候,設定主鍵

-- 單個欄位的主鍵
CREATE TABLE 表名(
	欄位名 資料型別 PRIMARY KEY
);

-- 多個欄位組合的主鍵
CREATE TABLE 表名(
	欄位名1 資料型別,
	欄位名2 資料型別,
	.....
	PRIMARY KEY(欄位名1, 欄位名2, 欄位名n)
);

2、唯一約束

唯一約束用於保證資料表中欄位值的唯一性,在 MySQL 中使用 UNIQUE 關鍵字新增唯一約束。在建立表時為某個欄位新增唯一約束的具體語法格式如下:

CREATE TABLE 表名(
	欄位名 資料型別 UNIQUE,
	....
);

注意:被定義成唯一約束的欄位,欄位值不能相同。但是可以為 NULL。

唯一約束也可以新增到已經建立完成的表中,語法格式如下:

ALTER TABLE 表名 ADD UNIQUE(列名);

3、自動增長列

資料表中的 id 欄位一般從1開始插入,不斷增加,每次插入新資料時,都要新增一個 id 欄位的值,當資料內容龐大時,容易出錯。為了解決這個問題,可以將 id 欄位的值設定為自動增加。在 MySQL 中使用 AUTO_INCREMENT 關鍵字設定表字段值自動增加。在建立表時將某個欄位的值設定為自動增長,語法格式如下:

CREATE TABLE 表名(
	欄位名 資料型別 AUTO_INCREMENT,
	....
);

此外,也可以為已經建立完成的表字段設定自動增長列,語法格式如下:

ALTER TABLE 表名 MODIFY 欄位名 資料型別 PRIMARY KEY AUTO_INCREMENTL;

二、參照完整性

MySQL參照完整性一般是通過MySQL外來鍵(foreign key)實現的

刪除參照約束

ALTER 表 DROP FOREIGN KEY fg_fk;

給現有表增加參照約束

ALTER TABLE`score`ADD CONSTRAINT`score_fk2`FOREIGN KEY (`sid`) REFERENCES`student`(`sid`);

資料庫系統的外來鍵值更新模式一般有3種:

  • 預設的外來鍵管理是Restict,即限制方式。前面實驗我們已經見識了這種方式的作用。

  • CASCADE,即級聯方式,可以理解為株連九族,即主鍵改變後,引用它的外來鍵值自動改變成新主鍵值來保證參照完整性。

  • SET NULL,置空,即主鍵值改變後,引用它的外來鍵值自動改為NULL來保證參照完整性。

eg

alter table 表名
add constraint fk_js foreign key(任課教師編號) references teacher (工號) on update cascade;

三、使用者自定義完整性

像MS SQL Server等資料庫管理系統有CHECK約束可以很方便地實現使用者自定義完整性約束。但MySQL沒有提供真正的CHECK約束。但使用者自定義約束的原理都差不多,通過觸發器就可以實現。

例如:學生年齡不能取負值的約束

-- insert 觸發器 年齡不能為負
delimiter ;
delimiter $$

create trigger st_ins_chk_age before insert
  on student
  for each row
begin
  if new.年齡 is not NULL and new.年齡 < 0 then
    signal sqlstate 'HY000'
    set message_text = "年齡不能為負";
  end if;
end$$

-- update 觸發器 年齡不能為負
delimiter ;
delimiter $$

create trigger st_up_chk_age before update
  on student
  for each row
begin
  if new.年齡 is not NULL and new.年齡 < 0 then
    signal sqlstate 'HY000'
    set message_text = "年齡不能為負";
  end if;
end$$

delimiter ;

附加

不用外來鍵,而利用觸發器實現socre的課號要級聯參照course中的課號?

score 表

-- 觸發器 實現 score 外來鍵 學號 參照 student 學號 -- score
delimiter ;
delimiter $$

create trigger sc_fk_ins_xh before insert
  on score
  for each row
begin
  if (select count(*) from student where 學號=new.學號)=0 and new.學號 is not NULL then
    signal sqlstate 'HY000'
    set message_text = "Cannot add or update a child row: a foreign key constraint ...";
  end if;
end$$

create trigger sc_fk_up_xh before update
  on score
  for each row
begin
  if (select count(*) from student where 學號=new.學號)=0 and new.學號 is not NULL then
    signal sqlstate 'HY000'
    set message_text = "Cannot add or update a child row: a foreign key constraint ...";
  end if;
end$$

delimiter ;

注意:score 中是 new ,student 中是 old

student 表

-- 觸發器 實現 score 外來鍵 學號 參照 student 學號 -- student
delimiter ;
delimiter $$

create trigger st_del_xh before delete
  on student
  for each row
begin
  if (select count(*) from score where 學號=old.學號)>0 then
    signal sqlstate 'HY000'
    set message_text = "Cannot delete or update a child row: a foreign key constraint ...";
  end if;
end$$

create trigger st_up_xh before update
  on student
  for each row
begin
  if (select count(*) from score where 學號=old.學號)>0 then
    signal sqlstate 'HY000'
    set message_text = "Cannot delete or update a child row: a foreign key constraint ...";
  end if;
end$$

delimiter ;