1. 定义若干表,其中包括primary key, foreign key和check的定义。
create shema company; use company; create table employee (employee_name varchar(20), street varchar(15), city varchar(15), primary key(employee_name)); createtable company (company_namevarchar(20), city varchar(15), primary key(company_name)); create table works (employee_name varchar(20), company_name varchar(20), salary int, primary key(employee_name), foreign key(company_name)references company(company_name) on delete set null on update cascade, foreign key(employee_name)references employee(employee_name) on delete cascade on update cascade, check(salary>1000)); create table manages (employee_namevarchar(20) , manager_name varchar(20) , primary key(employee_name), foreign key(employee_name)referencesemployee(employee_name) on delete cascade on update cascade, foreign key(manager_name)references employee(employee_name) on delete set null on update cascade);
创建成功:
2.让表中插入数据,考察primary key如何控制实体完整性。
insert into company values ('Bertelsmann','Cambridge'); insert into company values ('Chloris','Nottingham'); insert into company values ('Eldat GmbH','Birmingham'); insert into company values ('Greenteam','Cambridge'); insert into employee values ('Dean','Dover','Sheffield'); insert into employee values ('Whitney','Regent','Nottingham'); insert into employee values ('Amanda','King','Birmingham'); insert into employee values ('Richard','Strand','Cambridge'); insert into employee values ('Kevin','King','Birmingham'); insert into employee values ('Betty','Strand','Cambridge'); insert into employee values ('Mark','Dover','Sheffield'); insert into employee values ('Lily','Regent','Nottingham'); insert into works values ('Whitney','Chloris',2500); insert into works values ('Mark','Chloris',4000); insert into works values ('Dean','Eldat GmbH',3100); insert into works values ('Amanda','Greenteam',2800); insert into works values ('Richard','Bertelsmann',3000); insert into works values ('Kevin','Greenteam',2700); insert into works values ('Betty','Bertelsmann',3200); insert into works values ('Lily','Eldat GmbH',3800); insert into manages values ('Whitney','Mark'); insert into manages values ('Dean','Lily'); insert into manages values ('Kevin','Amanda'); insert into manages values ('Richard','Betty');
插入成功:
employee表中已经存在员工Betty(主码),我们再插入一个名为Betty的员工,插入被禁止,违背了主码约束。所以最好将主码改为id,而不是员工名。
3. 删除被引用表中的行,考察foreign key 中on delete 子句如何控制参照完整性。
我们删除employee表中的员工Betty的信息,有两张表works和manages都参照了它,我们来查看删除后的三张表:
在works表中,设置employee_name属性为级联删除,所以works表中与Betty有关的元组也被删除。
在manages表中,设置manager_name属性为set null的非级联删除,所以manager_name变为NULL,该行未被删除。
4. 修改被引用表中的行的primary key,考察foreign key 中on update 子句如何控制参照完整性。
我们修改employee表中的员工Amanda的名字为Amy,有两张表works和manages都参照了它,我们来查看修改后的三张表: 由于设置了级联更新,所以所有Amanda名字都变成了Amy。
5. 修改或插入表中数据,考察check子句如何控制校验完整性。
我们插入一组工资小于1000的员工(违背check约束),但是,插入成功了。mysql并没有实现check约束:
使用trigger可以实现这一功能。
delimiter || create trigger check_minimum_salary after insert on works for each row begin if new.salary<1000 then delete from works where works.employee_name=new.employee_name; end if; end; || delimiter ;
mysql提供了delimiter对结束语句标识进行重定义,在这里我们将其定义为||,trigger定义结束后又将结束标识恢复为分号。同样,这里可以采用rollback。
完成触发器后,再尝试插入小于900的工资,插入失败:
6. 定义一个asseration, 并通过修改表中数据考察断言如何控制数据完整性。
create assertion minimum_salary check(salary>1000);
mysql并不支持assertion,它同样只能通过trigger实现,和5中的触发器相同。当然,我们还需要delete、update时的触发器。此时修改工资小于1000会被拒绝。
7. 定义一个trigger, 并通过修改表中数据考察触发器如何起作用。
为了便于trigger的书写,我们先为company表新增一个属性:tot_salary,一开始都为NULL:
update company as T set T.tot_salary = (select sum(salary) from works as R group by company_name having R.company_name = T.company_name);
这时,定义一个维护tot_salary始终为所有员工薪水和的trigger语句:
delimiter || create trigger check_total_salary_insert after insert on works for each row begin update company set tot_salary = tot_salary + new.salary where company.company_name = new.company_name; end;|| create trigger check_total_salary_update after update on works for each row begin update company set tot_salary = tot_salary + new.salary - old.salary where company.company_name = new.company_name; end;|| create trigger check_total_salary_delete after update on works for each row begin update company set tot_salary = tot_salary - old.salary where company.company_name = old.company_name; end;|| delimiter ;
之后,我们插入新的员工信息:
再去查看company表,发现Eldat GmbH公司的tot_salary已自动更新。