数据库工程开发秘籍之TSQL 存储过程user stored procedure的概念与案例实战

Posted ShenLiang2025

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了数据库工程开发秘籍之TSQL 存储过程user stored procedure的概念与案例实战相关的知识,希望对你有一定的参考价值。

TSQL存储过程概念与案例实战

存储过程

存储过程由一个或多个 T-SQL 语句或对.NET公共语言运行时 (CLR) 方法的引用所构成的一组程序块。这里的T-SQL语句包括执行DDL、DML语句、应用临时表、动态SQL、定义异常处理等。但是相比于函数,它不能嵌套在查询里,但它可以调用其它的存储过程,即存储过程可以相互调用。

存储过程和常见的程序语言类似,可以指定输入和输出参数。SQL Server通过缓存存储过程的执行计划进而达到节约时间、降低CPU、内存的目的。

存储过程相对于在应用端实现业务逻辑有以下好处:

1 通过封装实现重用性和逻辑复杂性的隐藏。仅需要通过存储过程的修改(alter procedure)就能应用新的逻辑。

2 减少网络的传输,这是因为存储过程即存储在数据库里,而如果是应用程序方式访问数据库识别有网络传输的成本。

3 存储过程可以提供对数据库进行安全的访问,即赋予了执行存储过程的用户不能直接访问底层的数据库对象,这种隔离对数据库提供了保障。

补注:尽管存储过程有这些优点,但实际应用程序封装在Service(服务层),其对应的是某些单独的SQL逻辑,而如果都放在存储过程则会出现灵活性差、代码难维护的情况。

普通存储过程

假设我们有一张tb_user表,有两个字段id,name,如果我想通过传参数的形式给这张表插入数据,那么我们可以通过存储过程来实现。这里id需要沿着tb_user的最大的值往下自增,自增间隔是1。

SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[usp_useradd_MS]
(@username VARCHAR(100))
AS
DECLARE @max_id int=0
DECLARE @has int=0
BEGIN
SELECT @max_id=max(id) FROM tb_user  ;
SELECT @has=1 FROM tb_user WHERE name = @username;
  IF @has =0
    BEGIN
        INSERT INTO tb_user VALUES(@max_id+1,@username);
    END;

END;
GO

--调用,可选用下列任一方式执行
exec usp_useradd_MS 'Mike' exec usp_useradd_MS @username='John' 
--验证结果
SELECT * FROM tb_user;

存储过程与动态SQL

所谓动态SQL即SQL的内容是灵活的,是通过字符串拼接出来的,可以理解是不固定的。比如有一个需求,我们想通过查询指定表的字段名并以列的形式展示出来,这里就可以通过存储过程结合动态SQL来实现。因为每次传过来的参数即表名是不固定的,所以需要一个字符串变量拿到参数里的值再拼接成最终的sql(相对于翻译一下),再去数据库里执行。

CREATE PROCEDURE [dbo].[usp_getColumnsBycolumn]( @tabname VARCHAR(100)) 
AS 
DECLARE @sql VARCHAR(8000) 
DECLARE @STRING VARCHAR(500) 
BEGIN   
	SELECT @sql= ISNULL(@sql+',','')+'['+CAST(COLID AS VARCHAR(12))+']'   
	FROM SYSCOLUMNS    
	WHERE ID = OBJECT_ID(@tabname) 
	GROUP BY COLID   
	SET @STRING='SELECT * FROM (SELECT NAME,COLID FROM SYSCOLUMNS WHERE ID=OBJECT_ID('''+@tabname+'''))A pivot (MAX(NAME) for COLID in('+@sql+'))t'   
	EXEC(@STRING) 
END 
GO 
--调用及结果
exec usp_getColumnsBycolumn 'tb_user'

存储过程内调用存储过程

存储过程里是可以调用其它存储过程的,有时一些复杂的逻辑需要多个存储过程结合一起才能实现最终效果。

CREATE PROCEDURE [dbo].[usp_getColumnsByonecolumn]( @tabname VARCHAR(100)) 
AS 
DECLARE @tab Table (colid varchar(100),colname varchar(20)) 
BEGIN 
	INSERT INTO @tab exec usp_getColumnsBycolumn  @tabname 
	SELECT colid FROM @tab 
END
--调用
exec usp_getColumnsByonecolumn 'tb_user'
-- 结果

注意:我们不可以把存储过程包裹在子查询里,即如下方式查询存储过程的结果是不支持的。

SELECT * FROM(exec usp_getColumnsBycolumn 'tb_user')A

系统函数查看存储过程的定义

可以通过内置的系统函数sp_helptext查看存储过程的文本定义。

sp_helptext @objname = N'usp_getColumnsByonecolumn'
#结果,存储过程的文本定义见下:
CREATE PROCEDURE [dbo].[usp_getColumnsByonecolumn]( @tabname VARCHAR(100))
AS
DECLARE @tab Table
  (
   colid varchar(100), 
   colname varchar(20)
  )
BEGIN
INSERT INTO @tab exec usp_getColumnsBycolumn  @tabname
SELECT colid FROM @tab
END

存储过程的安全性

存储过程跟表、视图一样首先用户和角色,赋予EXECUTE权限后才能执行。特别的,如果过程里用到非dbo的schema(架构)那么在赋予存储过程权限后也要将该架构下表的访问权限赋予用户,否则存储可以执行但是会报底层表访问权限的错误。

CREATE LOGIN db_loginuser WITH PASSWORD = 'D#2$3)5b'; 
GO CREATE USER db_user FOR LOGIN db_loginuser; 
GO  EXECUTE AS LOGIN = 'db_loginuser'; 
SELECT SUSER_NAME() AS [login], USER_NAME() AS [user];

exec usp_useradd_MS 'Alice'

 

REVERT; 
SELECT SUSER_NAME() AS [login], USER_NAME() AS [user];

GRANT EXEC ON dbo.usp_useradd_MS TO db_user;
EXECUTE AS LOGIN = 'db_loginuser'; 
SELECT SUSER_NAME() AS [login], USER_NAME() AS [user];
exec usp_useradd_MS 'Alice' 

 

REVERT; 
SELECT * FROM tb_user 

:针对sa、dbo无法执行,即无法通过下列的语句切换到sa用户

EXECUTE AS LOGIN = 'sa';

EXECUTE AS LOGIN = 'dbo';

可通过REVERT;语句切换到上一次的用户执行环境。

存储过程与事务

事务是一个工作整体,它包含一个或多个操作数据(可能还包括数据结构)的活动。比如我们建表的DDL语句就是一个事务,要么建表成功要么失败,不存在中间状态。事务具有ACID性,其中A(atomicity)即原子性、C(consistency)即一致性、I(isolation)隔离性、D(durability)持久性。

SQL Server事务分为隐性事务和显性事务的,如果是隐性的可通过SET IMPLICIT_TRANSACTIONS ON;开关打开该选项,在该模式下只需要在要操作的事务的尾部编写commit或者rollback即可提交或者回滚事务,而不用在事务开头写begin tran。相对的显式事务需要在事务前后定义诸如BEGIN TRAN … COMMIT TRAN(ROLLBACK TRAN)

隐式事务的例子:

SET IMPLICIT_TRANSACTIONS ON 
select @@TRANCOUNT 
INSERT INTO tb_user VALUES(110,'Philips') 
select @@TRANCOUNT
-- 注:以上代码需要一起执行。
-- 查看插入的数据
SELECT * FROM tb_user A WHERE A.name = 'Philips'
--这里如果回滚则数据不存在。
ROLLBACK 

以回滚为例演示在存储过程里如何使用事务。如果传入的参数(用户名)是'Lily'则回滚,其它则插入并提交事务。

CREATE PROCEDURE [dbo].[usp_useradd_MS_trans](@username VARCHAR(100)) 
AS 
BEGIN   
	print @username;   
	if @username='Lily'   
	BEGIN     
		BEGIN TRAN     
			exec usp_useradd_MS @username     
		ROLLBACK TRAN     
	END   
	ELSE    
	BEGIN     
			exec usp_useradd_MS @username   
	END 
END 
GO
-- 执行与结果
EXEC usp_useradd_MS_trans 'Lily'
EXEC usp_useradd_MS_trans 'Tim'

SELECT * FROM tb_user A WHERE A.name = 'Lily'

SELECT * FROM tb_user A WHERE A.name = 'Tim'

以上是关于数据库工程开发秘籍之TSQL 存储过程user stored procedure的概念与案例实战的主要内容,如果未能解决你的问题,请参考以下文章

Tsql如何在链接服务器中获取存储过程中使用的列

表连接Tsql基本编程和存储过程

tsql 执行存储过程

TSQL NOLOCK VIEW 和存储过程

2017-3-16 Tsql基础编程 存储过程 触发器 级联删除

SSISDB5:使用TSQL脚本执行Package