本文仅供参考学习使用,谢谢
利用T-SQL 以存储过程和触发器实现编程
CREATE PROCEDURE <存储过程名>
[<参数列表>]
AS
<过程体>
//参数格式为:
@ 参数名 数据类型 [=缺省值] [OUTPUT]
//存储过程可以分为无参数和有参数两种
//有参数的又可以分为 带OUTPUT 和 不带OUTPUT 两种
过程体:是实现存储过程功能的一组T-SQL语句,可以包含任意多的SQL语句。
eg:
//创建一个不带参数的存储过程,完成查询每位学生的选课情况及其成绩。
CREATE PROCEDURE Proc1
AS
SELECT Student.Sno,Sname,Course.Cno,Cname,Grade
FROM Student,Course,SC
WHERE Student.Sno=SC.Sno
AND Course.Cno=SC.Cno
eg:
//创建一个带参数的存储过程,完成查询指定课程的选修情况。
CREATE PROCEDURE Proc2 @x CHAR(2)
AS
SELECT Student.Sno,Sname,Course.Cno,Cname,Grade
FROM Student,Course,SC
WHERE Student.Sno=SC.Sno
AND Course.Cno=SC.Cno and SC.Cno=@x
ORDER by SC.Sno
eg:
//创建一个带参数并有返回值的存储过程,完成输出指定学号的学生的‘2’号课程的成绩,并将结果,赋给一输出参数。
CREATE PROCEDURE Proc3
@x CHAR(5),@vgrade INT OUTPUT
AS
SELECT @vgrade=Grade FROM SC
WHERE Sno=@x AND Cno=‘2’
RETURN
--创建名为 GetStuCou_Ext 的返回多个结果集的存储过程
create procedure GetStuCou_Ext
@StuNo nvarchar(64),
@Height nvarchar(32)
as
begin
declare @Var nvarchar(10) --定义变量
set @Var='123' --赋值变量
--定义表变量
declare @StuTab table
(
ID int not null primary key,
StuNo nvarchar(50) unique,
Name varchar(50),
Sex varchar(10),
Height varchar(10)
)
--表变量只能在定义的时候添加约束
--定义临时表
create table #Tab
(
ID int not null primary key,
StuNo nvarchar(50),
Name varchar(50),
Sex varchar(10),
Height varchar(10)
)
alter table #Tab add constraint S_UNIQUE unique(StuNo)
--临时表可以在之后添加约束
if(@StuNo is not null and @StuNo <> '')
begin
insert into @StuTab(ID,StuNo,Name,Sex,Height) --把数据插入表变量
select S_Id,S_StuNo,S_Name,S_Sex,S_Height
from Student
where S_StuNo=@StuNo
insert into #Tab(ID,StuNo,Name,Sex,Height) --把数据插入临时表
select S_Id,S_StuNo,S_Name,S_Sex,S_Height
from Student
where S_StuNo=@StuNo
end
if(@Height is not null and @Height <> '')
begin
insert into @StuTab(ID,StuNo,Name,Sex,Height) --把数据插入表变量
select S_Id,S_StuNo,S_Name,S_Sex,S_Height
from Student
where S_Height=@Height
insert into #Tab(ID,StuNo,Name,Sex,Height) --把数据插入临时表
select S_Id,S_StuNo,S_Name,S_Sex,S_Height
from Student
where S_Height=@Height
end
SELECT * FROM @StuTab
select * from #Tab
end
--执行名为 GetStuCou_DSS 的返回多个结果集的存储过程
execute GetStuCou_Ext '005','185'
在SQL Server中,使用EXECUTE语句执行存储过程。
EXECUTE语句一般格式如下:
EXEC [UTE] <存储过程名> [ [过程参数变量=] { 值| 变量 [OUTPUT] }
eg:
//执行例2定义的存储过程。
EXEC Proc2 @x=’3’
//或
EXEC Proc2 ’3’
eg:
//执行例8定义的存储过程。
DECLARE @v1 CHAR(5),@v2 INT
SELECT @v1=’00101’
EXEC Proc3 @v1,@v2 OUTPUT
SELECT @v2
修改存储过程:
ALTER PROC[EDURE] <存储过程名> {同定义}
删除存储过程:DROP PROCEDURE
DROP PROC [EDURE] <存储过程名>
SQL Server系统存储过程是为管理员而提供的,SQL Server安装时在master数据库中创建并由系统管理员拥有。使用户可以很容易地从系统表中取出信息,管理数据库,并执行涉及更新系统表的其他任务。系统存储过程命令均以sq_打头,其作用进行数据库管理。
SQL Server提供了许多系统存储过程以方便检索和操纵存放在系统表中的信息,系统存储过程可以在任意一个数据库中执行。
例如,常用的系统存储过程有:
sp_addlogin [ @loginame = ] 'login'
[ , [ @passwd = ] 'password' ]
[ , [ @defdb = ] 'database' ]
[ , [ @deflanguage = ] 'language' ]
[ , [ @sid = ] sid ]
[ , [ @encryptopt= ] 'encryption_option' ]
扩展存储过程提供一种类似于存储过程的方式,它们是动态装入和执行的动态连接库(DLL)内的函数,无缝地扩展SQL Server功能。SQL Serve之外的动作可以很容易地触发,外部信息返回到SQL Server。另外,扩展存储过程支持返回状态码和输出。
注意:必须从master数据库执行扩展存储过程。
用户可以创建自己的扩展存储过程。
例如,下面是一些的扩展存储过程:
是从连接到不同服务器的远程服务器或客户机调用的存储过程。
局部存储过程在各个用户数据库中创建。只能由创建它的用户调用。
函数和存储过程的异同:
同:都是持久性存储模块
异:函数必须指定返回的类型
CREATE FUNCTION 函数名 ([参数1,参数2,...])
RETURNS <类型> AS <过程化SQL块>;
CALL/SELECT 函数名 ([参数1,参数2,...]);
重命名:
ALTER FUNCTION 过程名1 RENAME TO 过程名2;
重新编译:
ALTER FUNCTION 过程名 COMPILE;
ﰁ
补充:
使用触发器时,SQL Server提供了两张特殊的临时表:
inserted表和deleted表。
eg:
假设学生表S新增一属性Cnum(类型为INT,初值均为0), 记录该学生的选课数,分别创建如下触发器:
(1)INSERT 触发器
//创建INSERT 触发器Tri1,其功能是:在学习表SC插入一条记录后,立即更新学生表S的Cnum属性,即将原值加一。
CREATE TRIGGER Tri1 ON SC
FOR INSERT
AS
UPDATE Student SET Cnum=Cnum+1
WHERE Student.Sno=
(SELECT Sno FROM inserted
WHERE Student.Sno=inserted.Sno)
⑵ DELETE触发器
//创建DELETE 触发器Tri2,其功能是:在删除学习表SC一条记录后,立即更新学生表S的Cnum属性,即将原值减一。
CREATE TRIGGER Tri2 ON SC
FOR DELETE
AS
UPDATE Student SET Cnum=Cnum-1
WHERE Student.Sno=
(SELECT Sno FROM deleted
WHERE Student.Sno=deleted.Sno)
⑶ UPDATE触发器
//创建UPDATE 触发器Tri3,功能是:在SC表更新一条记录的学号后,立即更新学生表S的Cnum属性,改前学号学生的Cnum值减1,改后学号学生的Cnum值加1。
CREATE TRIGGER Tri3 ON SC
FOR UPDATE
AS
IF UPDATE(Sno)
BEGIN
UPDATE Student SET Cnum=Cnum-1
WHERE Student.Sno=(
SELECT Sno
FROM deleted
WHERE Student.Sno=deleted.Sno)
UPDATE Student SET Cnum=Cnum+1
WHERE Student.Sno=(
SELECT Sno
FROM inserted
WHERE Student.Sno=inserted.Sno)
END
MSSQL:
//Trigger on an INSERT, UPDATE, or DELETE statement to a table or view (DML Trigger)
CREATE 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
//Trigger on a CREATE, ALTER, DROP, GRANT, DENY, REVOKE, or UPDATE STATISTICS statement (DDL Trigger)
CREATE TRIGGER trigger_name
ON { ALL SERVER | DATABASE }
[ WITH <ddl_trigger_option> [ ,...n ] ]
{ FOR | AFTER } { event_type | event_group } [ ,...n ]
AS { sql_statement [ ; ] [ ,...n ] | EXTERNAL NAME < method specifier > [ ; ] }
<ddl_trigger_option> ::=
[ ENCRYPTION ]
[ EXECUTE AS Clause ]
<method_specifier> ::=
assembly_name.class_name.method_name
//Trigger on a LOGON event (Logon Trigger)
CREATE TRIGGER trigger_name
ON ALL SERVER
[ WITH <logon_trigger_option> [ ,...n ] ]
{ FOR| AFTER } LOGON
AS { sql_statement [ ; ] [ ,...n ] | EXTERNAL NAME < method specifier > [ ; ] }
<logon_trigger_option> ::=
[ ENCRYPTION ]
[ EXECUTE AS Clause ]
<method_specifier> ::=
assembly_name.class_name.method_name
//表的拥有者才可以在 表上创建触发器
CREATE TRIGGER <触发器名> //触发器名可以包含模式名,也 可以不包含模式名
//同一模式下,触发器名必须是 唯一的
//• 触发器只能定义在基本表上,不能定义 在视图上
//• 当基本表的数据发生变化时,将激活定 义在该表上相应触发事件的触发器
{BEFORE | AFTER} <触发事件> ON <表名> //触发事件:
//AFTER/BEFORE是触发的时机 //• INSERT、DELETE或UPDATE
//• AFTER表示在触发事件的操作执行之后激活触发器 //• 几个事件的组合
//• BEFORE表示在触发事件的操作执行之前激活触发器 //• UPDATE OF<触发列,...>
REFERENCING NEW|OLD ROW AS <变量> FOR EACH {ROW | STATEMENT}
//触发器类型
//• 行级触发器(FOR EACH ROW)
//• 语句级触发器(FOR EACH STATEMENT)
[WHEN <触发条件>]<触发动作体>
//• 触发器被激活时,只有当触发条件为真时触发动作体才执行;否则触发动作体不执行。
//• 如果省略WHEN触发条件,则触发动作体在触发 器激活后立即执行
//• 触发动作体可以是一个匿名PL/SQL 过程块,也可以是对已创建存储过程的调用
//• 如果是行级触发器,用户都可以在过程体中使用NEW和OLD引用事件,之后的新值和事件之前的旧值
//• 如果是语句级触发器,则不能在触 发动作体中使用NEW或OLD进行引 用
//• 如果触发动作体执行失败,激活触 发器的事件就会终止执行,触发器 的目标表或触发器可能影响的其他 对象不发生任何变化
CREATE TRIGGER <触发器名>
{BEFORE | AFTER} <触发事件> ON <表名>
REFERENCING NEW|OLD ROW AS <变量>
FOR EACH {ROW | STATEMENT}
[WHEN <触发条件>]<触发动作体>
eg:
在TEACHER表上创建一个AFTER UPDATE触发器,
触发事件是UPDATE语句:UPDATE TEACHER SET Deptno=5;
假设表TEACHER有1000行
如果是语句级触发器,那么执行完该语句后,触发动作只发生一次
如果是行级触发器,触发动作将执行1000次
eg:
//当对表SC的Grade属性进行修改时,若分数增加了10%则将此次操作记录到下面表中:
//SC_U(Sno,Cno,Oldgrade,Newgrade)
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)
//将每次对表Student的插入操作所增加的学生个数 记录到表StudentInsertLog中。
CREATE TRIGGER Student_Count
AFTER INSERT ON Student
REFERENCING
NEW TABLE AS DELTA
FOR EACH STATEMENT
INSERT INTO StudentInsertLog (Numbers)
SELECT COUNT(*) FROM DELTA
触发器必须是一个已经创建的触发器,并且只能由具有相 应权限的用户删除
DROP TRIGGER <触发器名> ON <表名>;
INSERT:
表1 (ID,NAME)
表2 (ID,NAME)
当用户插入表1数据后,表2也被插入相同的数据
CREATE TRIGGER TRI1
ON 表1
FOR INSERT
AS
BEGIN
INSERT INTO 表2 SELECT * FROM INSERTED
END
GO
DELETE:
表1 (ID,NAME)
表2 (ID,AGE,GENDER)
当用户删除表1某条ID的数据后,表2相应ID的数据也被删除
CREATE TRIGGER TRI2
ON 表1
FOR DELETE
AS
BEGIN
DECLARE @id INT
SELECT @id FROM DELETED
DELETE 表2
WHERE ID = @id
END
GO
UPDATE:
表1 (ID,NAME)
表2 (ID,NAME)
当用户更改表1 NAME列数据后,表2相应ID的数据也同时更新
CREATE TRIGGER TRI3
ON 表1
FOR UPDATE
AS
IF UPDATE(NAME)
BEGIN
UPDATE 表2
SET A.NAME = B.NAME
FROM 表2 A, INSERTED B
WHERE A.ID = B.ID
END
GO
事务是作为单个逻辑工作单元执行的一系列操作。一个逻辑工作单元必须有四个属性,称为原子性、一致性、隔离性和持久性(ACID)
属性,只有这样才能成为一个事务。
事务必须是原子工作单元;对于其数据修改,要么全都执行,要么全都不执行。
事务在完成时,必须使所有的数据都保持一致状态。在相关数据库中,所有规则都必须应用于事务的修改,以保持所有数据的完整性。事务结束时,所有的内部数据结构(如 B 树索引或双向链表)都必须是正确的。
由并发事务所做的修改必须与任何其他并发事务所做的修改隔离。事务识别数据时数据所处的状态,要么是另一并发事务修改它之前的状态,要么是第二个事务修改它之后的状态,事务不会识别中间状态的数据。这称为可串行性,因为它能够重新装载起始数据,并且重播一系列事务,以使数据结束时的状态与原始事务执行的状态相同。
事务完成之后,它对于系统的影响是永久性的。该修改即使出现系统故障也将一直保持。
事务是单个的工作单元。如果某一事务成功,则在该事务中进行的所有数据修改均会提交,成为数据库中的永久组成部分。如果事务遇到错误且必须取消或回滚,则所有数据修改均被清除。
每条单独的语句都是一个事务。
每个事务均以 BEGIN TRANSACTION 语句显式开始,以 COMMIT 或 ROLLBACK 语句显式结束。
在前一个事务完成时新事务隐式启动,但每个事务仍以 COMMIT 或 ROLLBACK 语句显式完成。
只能应用于多个活动结果集 (MARS),在 MARS 会话中启动的 Transact-SQL 显式或隐式事务变为批处理级事务。当批处理完成时没有提交或回滚的批处理级事务自动由 SQL Server 进行回滚
可以使用 Transact-SQL 语句或 API 函数和方法来确定数据库引擎事务启动和结束的时间
可以使用 BEGIN TRANSACTION、COMMIT TRANSACTION、COMMIT WORK、ROLLBACK TRANSACTION、ROLLBACK WORK 和 SET IMPLICIT_TRANSACTIONS 语句来描述事务。这些语句主要用于 DB 库应用程序和 Transact-SQL 脚本(如使用 osql 命令提示实用工具运行的脚本)中。
数据库 API(如 ODBC、OLE DB、ADO 和 .NET Framework SQLClient 命名空间)包含用于描述事务的函数或方法。这些是数据库引擎应用程序中用于控制事务的主要机制
每个事务都必须只由其中一种方法管理。在对同一事务使用两种方法会导致出现不确定的结果。例如,不应先使用 ODBC API 函数启动一个事务,再使用 Transact-SQL COMMIT 语句完成该事务。这样将无法向 SQL Server ODBC 驱动程序通知已提交该事务。在这种情况下,应使用 ODBC SQLEndTran 函数结束该事务
BEGIN { TRAN | TRANSACTION }
[ { transaction_name | @tran_name_variable }
[ WITH MARK [ 'description' ] ]
]
[ ; ]
参数
分配给事务的名称。transaction_name 必须符合标识符规则,但标识符所包含的字符数不能大于 32。仅在最外面的 BEGIN…COMMIT 或 BEGIN…ROLLBACK 嵌套语句对中使用事务名。
用户定义的、含有有效事务名称的变量的名称。必须用 char、varchar、nchar 或 nvarchar 数据类型声明变量。如果传递给该变量的字符多于 32 个,则仅使用前面的 32 个字符;其余的字符将被截断。
指定在日志中标记事务。description 是描述该标记的字符串。如果 description 是 Unicode 字符串,那么在将长于 255 个字符的值存储到 msdb.dbo.logmarkhistory 表之前,先将其截断为 255 个字符。如果 description 为非 Unicode 字符串,则长于 510 个字符的值将被截断为 510 字符。
如果使用了 WITH MARK,则必须指定事务名。WITH MARK 允许将事务日志还原到命名标记
eg:
BEGIN TRANSACTION t11 WITH mark 'aaa';
DECLARE @errorflag INT;
SET @errorflag = 1;
DELETE FROM Student WHERE Sno = '7777777';
IF @errorflag =- 1
BEGIN
ROLLBACK TRANSACTION t11;
RETURN;
END;
ELSE
BEGIN
DELETE FROM CJ WHERE Sno = '7777777';
COMMIT TRANSACTION t11;
END;
END;