[mysql] SQL数据完整性

1. 定义若干表,其中包括primary key, foreign keycheck的定义。


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');

        插入成功:

        [mysql] SQL数据完整性_第1张图片


        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都参照了它,我们来查看修改后的三张表:

        [mysql] SQL数据完整性_第2张图片

        由于设置了级联更新,所以所有Amanda名字都变成了Amy。

5. 修改或插入表中数据,考察check子句如何控制校验完整性。

        我们插入一组工资小于1000的员工(违背check约束),但是,插入成功了。mysql并没有实现check约束:

          [mysql] SQL数据完整性_第3张图片      


        使用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的默认结束语句,而定义trigger时出现; 时,trigger语句本身还没有结束,却因为读取到;强行结束,所以我们需要排除这一干扰。

         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:

        [mysql] SQL数据完整性_第4张图片
        我们通过以下代码更新tot_salary的值:

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);

        更新后的结果:

        [mysql] SQL数据完整性_第5张图片

        这时,定义一个维护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已自动更新。

        [mysql] SQL数据完整性_第6张图片

你可能感兴趣的:([mysql] SQL数据完整性)