sql server 练习3(Transcat-SQL程序设计,触发器和存储过程)

9 篇文章 4 订阅
8 篇文章 15 订阅

sql server 的Transcat-SQL程序设计,触发器和存储过程

  这篇博客主要简单讲一下sql server数据库的一些高级操作,那就是:Transcat-SQL语句,触发器和存储过程,由于边幅问题,这里这是简单地说一下概念,注意事项以及一些相关练习。

Transcat-SQL程序设计

  我们平常在大多数数据库中用到的SQL语句,都是标准的SQL语句,是不支持流程控制。

  Transcat-SQL就是在标准SQL的基础上进行扩充而推出的SQL server专用的结构化SQL,引入了程序设计的思想、增强了程序的流程控制语句等。

  Transcat-SQL主要包含变量、运算符、批处理、流程控制语句、常用命令这五部分。这里说一下批处理和流程控制语句,因为我觉得这部分是之前我没有理解到的。

批处理

  批处理是包含一个或多个的T-SQL语句的组,批处理的所有语句被整合成一个执行计划。一个批处理内的所有语句要么被放在一起通过解析,要么没有一句能够执行。

  批处理是使用GO语句将多条SQL语句进行分割,其中每两个GO之间的SQL语句就是一个批处理处理单元。

如以下是一个批处理,会都执行,或都不执行:

use teach
go
select * from SC
select count(*) from s
go
流程控制语句

T-SQL的流程控制语句主要有以下几种:

1.begin end

begin
    <命令行或程序块>
end

2.if…else

if <条件表达式>
    <命令行或程序块>
[else 
    <命令行或程序块>]

3.if[not] exists

if [not] exists (select 子查询)
    <命令行或程序块>
[else
    <命令行或程序块>]

4.case语句
(格式一)如果比较两个表达式的值为相等,返回then后的,否则,测试下一条

case <表达式>
    when <表达式> then <表达式>
    。。。
    when <表达式> then <表达式>
    [else <表达式>]
end

(格式二)如果表达式的值为真,返回then后的,否则,测试下一条

case
    when <表达式> then <表达式>
    。。。
    when <表达式> then <表达式>
    [else <表达式>]
end

注意如果在case语句中没有else子句,则返回null
5.while…continue…break

while <条件表达式>
begin
    <命令行或程序块>
    [break]
    [continue]
    [命令行或程序块]
end

6.waitfor

waitfor {delay <'时间'> | time <'时间'>
            | errorexit | processexit | mirrorexit}

7.goto
goto 标志符

8.return

return([整数值])
存储过程

存储过程(stored procedure)是存储在SQL server数据库中的一种编译对象。它是一组为了完成特定功能的SQL语句集,这些SQL语句集经编译后存储在数据库中,可以被客户机管理工具、应用程序和其他存储过程代用,同时可以传递参数。简单来说,就是预编译好的SQL语句,能提高执行效率。

创建存储过程
create procedure procedure_name [ ; number ]
[{ @parameter data_type }
 [ varying ] [ = default ] [ output ]
] [ ,...n ]
[with 
    { recompile | encryption | recompile , encryption } ]
[for replication]
as sql_statement [ ,...n]

好长,举个例子应该更能清楚理解

定义能够返回值的存储过程。在Teach数据库中,创建一个名称为QueryTeach的存储过程。该存储过程的功能是从数据库S中根据学号查询某一同学的姓名和系别,查询的结果由参数@sn和@dept返回。

use teach
go
create procedure QueryTeach
(   @sno varchar(6),
    @sn nvarchar(10) output,
    @dept nvarchar(20) output
)
as
select @sn=SN,@dept=Dept from where sno=@sno
查看存储过程
-- 查看数据库Teach中存储过程MyProc的源代码
use teach
go
exec sp_heptext MyProc
删除存储过程
use teach 
go
if exists(select 1 from sysobjects where id=object_id('存储过程名') and xtype='P')  
drop procedure MyNewProc
执行存储过程
-- 执行数据库Teach中的带输出参数的存储过程QueryTeach,存储过程QueryTeach执行完毕后,所需结果保存在输出参数@sn@dept中。
use teach
go
declare @sn nvarchar(10)
declare @dept varchar(20)
-- 这里注意输入的参数,不能@参数名=参数值,来输入,只能直接输入参数值
exec QueryTeach 'S10',@sn output,@dept output
select '姓名'=@sn, '系别'=@dept
触发器

触发器是一种特殊的存储过程,其中包含一系列的T-SQL语句,但它的执行不是用execute命令显式调用,而是在满足一定条件下自动激活而执行,如向表中插入记录,更新记录,或者删除记录时被系统自动地激活并执行。
sql server2012提供了三种类型的触发器:DML触发器,DDL触发器和登录触发器。

创建触发器

这里主要说的DML触发器,因为这类触发器涉及到inserted和deleted表,比较复杂。
AFTER 触发器语法:

CREATE [ OR ALTER ] TRIGGER [ schema_name . ]trigger_name   
ON { table }   
[ WITH <dml_trigger_option> [ ,...n ] ]  
{ FOR | AFTER }   
{ [ INSERT ] [ , ] [ UPDATE ] [ , ] [ DELETE ] }   
AS { sql_statement  [ ; ] [ ,...n ] }  

<dml_trigger_option> ::=  
    [ NATIVE_COMPILATION ]  
    [ SCHEMABINDING ]  
    [ EXECUTE AS Clause ]

INSTEAD OF 触发器语法:

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 [ ; ] > }  

<dml_trigger_option> ::=  
    [ ENCRYPTION ]  
    [ EXECUTE AS Clause ]  

<method_specifier> ::=  
    assembly_name.class_name.method_name

  触发器的例子:

--Instead Of触发器:删除课程时,同时删除该课程的选课信息
IF OBJECT_ID (N'TRIGER_Courses_Instead_Delete', N'tr') IS NOT NULL
    DROP TRIGGER TRIGER_Courses_Instead_Delete;
GO
CREATE TRIGGER TRIGER_Courses_Instead_Delete
ON Courses
Instead Of DELETE
AS
    declare @courseId int
    --获取要删除的课程ID
    SELECT @courseId=ID FROM deleted
    --删除选课信息
    DELETE FROM SC WHERE CourseID = @courseId
    --删除课程信息
    DELETE FROM Courses WHERE ID=@courseId 
练习

1、说明下面代码段的功能

    SELECT  tname  as ‘姓名’,tSex  as ‘性别’,
    case trank
        when ‘教授’ then ‘高级职称’
        when ‘讲师’ then ‘中级职称’
    else
        ‘初级职称’
    end
from teacher

2、完成下面代码的书写
计算student_course表的平时分数列的平均值。如果小于80,则分数增加其值的5%;如果分数的最高值超过95,则终止该操作。在以下代码划线处填入适当的内容以完成上述功能。

Update student_course set normalmark=60
go
WHILE (SELECT  ________(normalmark) FROM student_course)<80
BEGIN
UPDATE student_course
SET normalmark = normalmark *1.05
if (SELECT MAX(normalmark) FROM student_course)>________      
    ________
END

3、根据要求完成下列题目

(1)编写一个触发器:在添加期末成绩信息时,利用平时成绩、其中成绩和期末成绩来计算成绩总评。如果没有期中成绩,则平时和期末成绩比重为2:8,如果有期中成绩,则平时、期中、期末三者比重为2:2:6。(假设表中有期中成绩列,且该列默认值为-1。)
(2)创建一个带输入参数和输出参数的存储过程,要求实现如下功能:输入学生学号,然后输出学生的选课门数、平均分以及所选学分。
(3)调用2小题中的存储过程,并分别获得输出相关信息。

4、思考题

(1)思考基于UPDATE操作的触发器的操作流程?

练习答案

use stuManage
go
-- 1.功能,从教师表查询出所有教师第姓名,性别和职称,并将名为教授的职称显示为“高级职称”,名为”讲师的职称显示为“中级职称,其他显示为初级职称。”
 SELECT  tname  as '姓名',tSex  as '性别',
    case trank
        when '教授' then '高级职称'
        when '讲师' then '中级职称'
    else
        '初级职称'
    end
from teacher;



select * from teacher;
select * from student_course;

-- 2、完整代码如下
Update student_course set normalmark=60
go
WHILE (SELECT  avg(normalmark) FROM student_course)<80
BEGIN
UPDATE student_course
SET normalmark = normalmark *1.05
if (SELECT MAX(normalmark) FROM student_course)>95
break
END

/*
3、根据要求完成下列题目

(1)编写一个触发器:在添加期末成绩信息时,利用平时成绩、其中成绩和期末成绩来计算成绩总评。如果没有期中成绩,则平时和期末成绩比重为28,如果有期中成绩,则平时、期中、期末三者比重为226。(假设表中有期中成绩列,且该列默认值为-1。)
(2)创建一个带输入参数和输出参数的存储过程,要求实现如下功能:输入学生学号,然后输出学生的选课门数、平均分以及所选学分。
(3)调用2小题中的存储过程,并分别获得输出相关信息。

(1)编写一个触发器:在添加期末成绩信息时,利用平时成绩、其中成绩和期末成绩来计算成绩总评。
如果没有期中成绩,则平时和期末成绩比重为28,如果有期中成绩,则平时、期中、期末三者比重为226。
(假设表中有期中成绩列(mid_mark),且该列默认值为-1。)
假设是要更新期末成绩列mark才有此需求
*/
use stuManage;
select * from student_course;
-- 增加期中成绩列
alter table student_course ADD mid_mark int;
-- 设置平时成绩和期末成绩,其中成绩
update student_course set examMark = 70;
update student_course set NormalMark = 80;
update student_course set mid_mark = -1;

-- alter table student_course drop column mid_mark;

select * from student_course;
select  * from sys.server_triggers;
select * from sys.triggers;
-- 建立触发器
use stuManage
go
if(OBJECT_ID('trigger_update_student_course_mark') is not null)       
drop trigger trigger_update_student_course_mark ;
go
Create trigger trigger_update_student_course_mark
on student_course
After update
As 
declare @s_no int,@cc_no int
select @s_no=sNo,@cc_no=ccNo from deleted   
print '要更新的学生id和学生课程号分别为:'+str(@s_no)+','+str(@cc_no);
begin
    -- 只有更新mark(期末成绩列才会执行以下过程,更新其他列不会执行)
    if (update(mark))
    if(select mid_mark from student_course where sNo=@s_no and ccNo=@cc_No)>=0   
    begin    
        update student_course set mark=(NormalMark*2+mid_mark*2+examMark*6)/10 
        where sNo=@s_no and ccNo=@cc_no; ;
    end

    else    
        update student_course set mark=(NormalMark*2+examMark*8)/10 
        where sNo=@s_no and ccNo=@cc_no;

end
go

select * from student_course;
-- 测试
update student_course set Mark=200 where sNO=081220101 and ccNO=0312091006;


-- (2)创建一个带输入参数和输出参数的存储过程,要求实现如下功能:输入学生学号,然后输出学生的选课门数、平均分以及所选学分。
use stuManage
go
if Exists(select name from sysobjects where NAME = 'get_student_course_avgMark_credit_by_sno' and type='P')
drop procedure get_student_course_avgMark_credit_by_sno
go
create procedure get_student_course_avgMark_credit_by_sno
( @sno int
)
as
select @sno,sumCredit as '所选学分',sumCourse as '课程门数',avgMark as '平均分数' from
(select sNo,sum(Credit) as sumCredit,count(student_course.ccNo) as sumCourse ,avg(mark) as avgMark
from student_course,course_class
where student_course.ccNO=course_class.ccNo group by sNO ) tempCredit
 where tempCredit.sNO=@sno;
go

-- (3)调用2小题中的存储过程,并分别获得输出相关信息。
-- 调用方法一
exec get_student_course_avgMark_credit_by_sno @sno=081220102;
-- 调用方法二(不用参数)
exec get_student_course_avgMark_credit_by_sno 081220102;

4、思考题

(1)思考基于UPDATE操作的触发器的操作流程?

答:基于update操作的触发器的操作是sql语句在执行更新操作时,首先将要更新的行删除,临时存放在delete表中,然后再将新的行插入到原来的表中,并且将新的行临时存放在inserted表中。最后,再执行触发器里面的语句。

总结

经过这次练习,自己对于SQL server的触发器和存储过程有了更深一步的认识,知道了存储过程的应用于使用实际应用中的好处,即能模块化的程序设计,高效率的执行,减少网络流量,可以作为安全机制使用。此外,在这次练习中对于Transaction-SQL中流程语句也有了一定的了解,因为之前操作数据库时都没有怎么用过T-sql语句,在这次练习中用到了许多流程语句,对于自己自身的关于T-sql的流程控制语句知识有了更深刻的认识。另外,还有对于sql server 的触发器也加深了理解,还学到了如何只对某列执行更新的时候,才使触发器起作用。

  • 8
    点赞
  • 31
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值