我们之前建表的时候已经用过这些,实体完整性和参照完整性我们之前已经做过例子,这里只进行简单的演示。
在列里面定义:
create Table Student
(Sno char(9) PRIMARY KEY,
Sname char(9) NOT NULL,
Ssex char(2),
Sage smallint,
Sdept char(20));
它也可以在行级定义,而且有些情况下, 比如两个列共同作为主码时,只能在行级定义。
create Table Student
(Sno char(9) ,
Sname char(9) NOT NULL,
Ssex char(2),
Sage smallint,
Sdept char(20),
PRIMARY KEY(Sno);
CREATE TABLE SC
(Sno NCHAR(11),
Cno NCHAR(4),
Grade SMALLINT,
PRIMARY KEY(Sno,Cno),
FOREIGN KEY (Sno) REFERENCES Student(Sno),
FOREIGN KEY (Cno) REFERENCES Course(Cno)
);
例码同上
要说明的是,这是针对被参照表的操作。参照表SC可以delete,insert一个不符合外键规则的直接拒绝;而被参照表,比如Student表,一个学生的信息修改了,那么sc表里是否跟着修改还是?
上图说明了有三种设置,拒绝,级联修改/删除,设置为空值。
create Table SC2
(Sno CHAR(9) NOT NULL,
Cno CHAR(4) NOT NULL,
Grade SMALLINT,
PRIMARY KEY (Sno, Cno),
FOREIGN KEY (Sno) REFERENCES Student(Sno)
on update cascade
on delete cascade,
FOREIGN KEY (Cno) REFERENCES Course(Cno)
on update cascade
on delete no action, --拒绝
);
这里分为属性上约束还有元组的约束。
列上的:not null,unique,check
元组上的:check
关于not null和unique,我们之前就做过例子,在这里不做示题
关于check
关于列的(也就是只独立处理一个属性的)
create Table Student2
(Sno char(9) PRIMARY KEY,
Sname char(9) NOT NULL,
Ssex char(2) check(Ssex IN('男','女')),--这里发生了变化
Sage smallint,
Sdept char(20));
create Table SC3
(Sno CHAR(9) NOT NULL,
Cno CHAR(4) NOT NULL,
Grade SMALLINT check (Grade>=0 AND Grade<=100),--这里发生了变化
PRIMARY KEY (Sno, Cno),
FOREIGN KEY (Sno) REFERENCES Student(Sno),
FOREIGN KEY (Cno) REFERENCES Course(Cno)
);
check里面就是写了个条件
关于行级的
create Table Student3
(Sno char(9) PRIMARY KEY,
Sname char(9) NOT NULL,
Ssex char(2) check(Ssex IN('男','女')),
Sage smallint,
Sdept char(20),
check (Ssex='女' OR Sname NOT like 'Mr.%')
);
CONSTRAINT <完整性约束条件名><完整性约束条件>
注意是子句,他也是嵌入到create里面写的。其实也就是多了一个关键字和一个你自己命名的名字。
这是列级的
create Table Student4
(Sno char(9)
constraint Student_PK_Sno PRIMARY KEY,--this
Sname char(9)
constraint Student_NN_Sname NOT NULL,--this
Ssex char(2)
constraint Student_check_Ssex check(Ssex IN('男','女')),--this
Sage smallint,
Sdept char(20),
check (Ssex='女' OR Sname NOT like 'Mr.%')
);
行级类似
create Table SC4
(Sno CHAR(9) NOT NULL,
Cno CHAR(4) NOT NULL,
Grade SMALLINT check (Grade>=0 AND Grade<=100),
constraint SC_PK PRIMARY KEY (Sno, Cno),
constraint SC_FK1 FOREIGN KEY (Sno) REFERENCES Student(Sno),
constraint SC_FK2 FOREIGN KEY (Cno) REFERENCES Course(Cno)
);
alter table Student4
drop constraint Student_PK_Sno;
通过先删除旧的,再添加新的方法修改。
alter table Student4
drop constraint Student_PK_Sno;
alter table Student4
add constraint Student_PK_Sno PRIMARY KEY(Sno,Sname);
断言是标准sql里的东西,t-sql并没有这个关键词。老师说可以用rule替代。
这里只做标准sql里的例子。
都是约束,为啥要用断言啊?直接check不好吗?
断言可以定义比较复杂的约束。
比如下面的例子:
我们之前的约束似乎没有办法做。
create assertion ASSE_SC_DB_NUM
check (60>=(select count(*)
from course,sc
where course.Cno=sc.Cno AND course.Cname='数据库'));
create assertion ASSE_SC_CNUM
check (60>=all(select count(*)
from sc
group by cno));
drop assertion asse_name
注意:T-SQL 中没有 ASSERTION 功能。 类似的有RULE,但使用方法不同: 上下文中不允许使用子查询,只允许使用标量表达式。 例如: CREATE RULE sex_rule AS @sex in (‘男’,‘女’) 使用Constraint基本能完成功能,不建议使用RULE。
CREATE TRIGGER语法格式
CREATE TRIGGER <触发器名>
{BEFORE | AFTER} <触发事件> ON <表名>
REFERENCING NEW|OLD ROW AS<变量> FOR EACH {
ROW | STATEMENT}
[WHEN <触发条件>]<触发动作体>
这是标准sql哈。
触发事件
触发事件可以是INSERT、DELETE或UPDATE
也可以是这几个事件的组合
还可以UPDATE OF<触发列,...>,即进一步指明修改哪些列时激活触发器
AFTER/BEFORE是触发的时机
AFTER表示在触发事件的操作执行之后激活触发器
BEFORE表示在触发事件的操作执行之前激活触发器
触发器类型
行级触发器(FOR EACH ROW)
语句级触发器(FOR EACH STATEMENT)
先创建表。
create table SC_U(Sno char(9),
Cno char(4),
Old smallint,
New smallint);
这是操作。
CREATE TRIGGER SC_T
AFTER UPDATE OF Grade ON SC
REFERENCING
OLD row AS OldTuple,
NEW row AS NewTuple
FOR EACH ROW
WHEN (NewTuple.Grade >= 1.1*OldTuple.Grade)
INSERT INTO SC_U(Sno,Cno,OldGrade,NewGrade)
VALUES(OldTuple.Sno,OldTuple.Cno,OldTuple.Grade,NewTuple.Grade);
但是我们发现sqlserver中上面的语句中报了错。
他的语法格式类似这种
-- SQL Server Syntax
-- Trigger on an INSERT, UPDATE, or DELETE statement to a table or view (DML Trigger)
CREATE [ OR ALTER ] TRIGGER [ schema_name . ]trigger_name
ON { table | view }
[ WITH <dml_trigger_option> [ ,...n ] ]
{ FOR | AFTER | INSTEAD OF }
{ [ INSERT ] [ , ] [ UPDATE ] [ , ] [ DELETE ] }
[ WITH APPEND ]
[ NOT FOR REPLICATION ]
AS { sql_statement [ ; ] [ ,...n ] | EXTERNAL NAME <method specifier [ ; ] > }
又查了好多博客,缺缺补补写出来了,但是不知道是否是标准写法。
首先referencing用了inserted和deleted表替代了;when语句我也不知道是否被替代了,但是可以用if来实现类似功能,但是是在那个过程里面执行的。
总之是实现那个功能了。
CREATE TRIGGER SC_T
ON SC
AFTER UPDATE
as
begin
declare @old int ,@new int ,@sno char(9), @cno char(4)
select @old=Grade from deleted
select @new=Grade from inserted
select @sno=Sno from inserted
select @cno=Cno from inserted
if(@new>=1.1*@old)
begin
insert
into SC_U(Sno,Cno,Old,New)
VALUES(@sno,@cno,@old,@new)
print'添加了一条数据---SC_U'
end
end;
(这个之前是80分)
(这个之前是95)看来是成功了。
还有就是关于for each row和for each statement,本来老师说可以做个实验加深一下印象,但是发现似乎sqlserver里面不能使用这个东西。(oracle支持)
标准sql:
CREATE TRIGGER Student_Count
AFTER INSERT ON Student
REFERENCING
NEW TABLE AS DELTA
FOR EACH STATEMENT
INSERT INTO StudentInsertLog (Numbers)
SELECT COUNT(*) FROM DELTA
create trigger Student_Count
on Student
after insert
as
begin
declare @oldnum int , @newnum int
select @oldnum= count(*) from deleted
select @newnum= count(*) from inserted
print 'old:'
print @oldnum
print ' new'
print @newnum
end
由此发现,deleted是删除的表,不是我刚开始想的 旧表;inserted是插入数据的表,而不是我以为的新表。
还有就是触发器这里t-sql和sql差的太多了。我百度了好久。
还有就是 五一竟然不放假?!
真的开学到现在还没歇过几天。
呜呜呜,晚安
终究还是我食言了,上午没能写完。现在是下午两点,继续:
CREATE TRIGGER Insert_Or_Update_Sal
BEFORE INSERT OR UPDATE ON Teacher
FOR EACH ROW
BEGIN
IF (new.Job='教授') AND (new.Sal < 4000)
THEN new.Sal :=4000;
END IF;
END;
至于删除触发器
DROP TRIGGER <触发器名> ON <表名>;
tsql里面不用加on和表明,也不能加。
先说标准sql
CREATE OR REPLACE PROCEDURE 过程名([参数1,参数2,...])
AS
<过程化SQL块>;
首先建表插数据哈
create table Account(Accountnum char(3),total float);
insert into Account values('01',100),('02',100);
create or replace procedure Transfer(inAccount int ,outAccount int, amount float)
as
declare
totalDepositOut float;
totalDepositIn float;
inAccountnum int;
begin
select total into totalDespositOut from Account
where Accountnum = outAccount;
if totalDespositOut is NULL then--没有转出账户
rollback;
return ;
end if;
if totalDespositOut<amount then--转出账户钱不够
rollback;
return ;
end if;
select Accountnum into inAccountnum from Account where Accountnum=inAccount;
if inAccountnum is null then
--没有转入账户
rollback;
return ;
end if;
update Account set total =total -amount
where Accountnum=outAccout;
update Account set total =total + amount
where Accountnum = inAccount;
commit;
end;
然后是t-sql
if (exists(select * from sys.objects where name = 'Proc_Transfer'))
drop procedure Proc_Transfer
go
create procedure Proc_Transfer
@inAccount int,@outAccount int,@amount float
as
begin transaction trans
declare
@totalOut float,
@totalIn float,
@inAccountnum int;
select @totalOut = total from Account where accountnum=@outAccount;
if @totalOut is NULL
begin
print'账户不存在或者没有存款'
rollback transaction trans;
return ;
end
if @totalOut<@amount
begin
print'账户余额不足'
rollback transaction trans;
return ;
end
select @inAccountnum=accountnum from account where accountnum=@inAccount;
if @inAccountnum is null
begin
print'转入用户不存在'
rollback transaction trans;
return ;
end
begin
update Account set total = total -@amount where accountnum= @outAccount;
update Account set total = total +@amount where accountnum =@inAccount;
print'OK!'
commit transaction trans;
return ;
end
CALL/PERFORM PROCEDURE
过程名([参数1,参数2,...]);
ALTER PROCEDURE 过程名1 RENAME TO 过程名2;
t-sql
ALTER { PROC | PROCEDURE } [schema_name.] procedure_name
[ { @parameterdata_type } [= ] ] [ ,…n ]
AS { [ BEGIN ] sql_statement [ ; ] [ ,…n ] [ END ] }
[;]
DROP PROCEDURE 过程名();
t-sql:
drop procedure 过程名;
函数就是加了返回值的存储过程
标准sql语法:
1. 函数的定义语句格式
CREATE OR REPLACE FUNCTION 函数名 ([参数1,参数2,…]) RETURNS <类型> AS <过程化SQL块>;
2. 函数的执行语句格式
CALL/SELECT 函数名 ([参数1,参数2,…]);
3. 修改函数
重命名
ALTER FUNCTION 过程名1 RENAME TO 过程名2;
重新编译
ALTER FUNCTION 过程名 COMPILE;
链接: t-sql函数.
感觉大作业需要使用sqlserver里的函数,但是现在不想看了,等过几周开始写大作业的时候用到的时候再细细看吧。
本篇完。