存储过程调用存储过程

from:https://www.cnblogs.com/zdkai/archive/2012/10/19/2730461.html

在存储过程中如何使用另一个存储过程返回的结果集

与这个问题具有相同性质的其他描述还包括:
如何在存储过程中检索动态SQL语句的执行结果?
如何实现类似SELECT * FROM (EXEC procedure_name @parameters_var) AS datasource WHERE ... 的功能?
procedure_name是一个存储过程的名字,@parameters_var是过程参数
如何将一个存储过程的执行结果记录集传递给另一个存储过程?
存储过程中如何根据另一个存储过程的执行结果选择执行流程?
存储过程中如何根据动态SQL语句的查询结果更改执行流程?
一个存储过程A使用另一个存储过程B的名字(或一段SQL语句或一个不确定的表名,字段名)作为参数,如何在不改动存储过程B的情况下,对存储过程B的执行结果记录集进行过滤/更改,再将过滤/更改后的结果集返回给存储过程A的调用者?

上面这些问题都有一个共同点,那就是都希望对存储过程(或动态SQL语句)的执行结果进行再处理,但是标准的SQL语句只能处理数据表,而一个存储过程(或动态SQL语句)的执行结果虽然是记录集,但它们本身不能当做数据表来处理。这样就大大限制了存储过程(或动态SQL语句)的应用范围,它们只能作为将记录集返回给应用程序前的最后一个处理层。如果我们可以像使用普通的数据表那样使用存储过程(或动态SQL语句)该有多好。
这个问题我以前的解决方法是使用OPENQUERY()或OPENDATASOURCE(),但OPENQUERY()不仅要求建立一个链接服务器,而且执行性能也让人无法满意。OPENDATASOURCE()则要求提供连接字符串,这对系统后期的维护也是一个很大的麻烦。
今天使用SQL Server联机丛书时无意中发现了一条SQL语句,竟然非常方便的解决了这个问题。这个语句就是INSERT语句。
INSERT语句在帮助中的定义是这样的:

INSERT [ INTO]
{ table_name WITH ( < table_hint_limited > [ ...n ] )
| view_name
| rowset_function_limited
}

{ [ ( column_list ) ]
{ VALUES
( { DEFAULT | NULL | expression } [ ,...n] )
| derived_table
| execute_statement
}
}
| DEFAULT VALUES

其中execute_statement的解释是"任何有效的 EXECUTE 语句,它使用 SELECT 或 READTEXT 语句返回数据。"。通常我们放在这个位置的就是一段SELECT语句。但帮助既然说"任何有效的 EXECUTE 语句",那么"EXEC procedure_name"也应该可以罗?想到这一点,马上决定动手验证一下。验证结果证实没问题。即下面这样的语句

INSERT INTO table_name EXEC procedure_name @parameters_var

确实可以正常工作。有了这个基础,我们也就有了解决本文开头那些问题的方法。

基本思路是先创建一个临时表,通过INSERT ... EXEC ...语句将存储过程的返回结果保存到临时表中,接下来就可以像处理普通数据表那样对待这个临时表了。对于动态SQL语句,可以通过dbo.sp_executesql存储过程执行,或者直接作为EXEC的参数执行。具体的编写要求可以参考SQL Server联机丛书。这里只特别说明一下,临时表的表结构与存储过程(或动态SQL语句)返回的记录集的表结构兼容即可,不要求完全相同。如果直接通过EXEC执行动态SQL语句,SQL语句有4K的长度限制。

最后给出两种最常见的处理流程:
1。创建一个临时表#tmp,表结构与目标存储过程procedure_name的返回结果集兼容(兼容即可,不必相同)。
CREATE TABLE #tmp(
[columns_list]
)
2。执行存储过程并将存储过程的返回结果集插入临时表。
INSERT INTO #tmp EXEC procedure_name @parameters_var
3。现在可以使用(过滤,更改或检索)#tmp了。^_^
IF EXISTS(SELECT * FROM #tmp)
BEGIN
--执行分支1
END ELSE BEGIN
--执行分支2
END
4。别忘了最后清除临时表。
DROP TABLE #tmp

对于动态SQL语句,只要将第二步改为
INSERT INTO #tmp EXEC dbo.sp_executesql @querystring_var
即可。

例子:

被调用的存储过程:

USE [NewITMS]
GO

/****** Object: StoredProcedure [dbo].[usp_Func_GetFuncByUserID] Script Date: 2018/3/6 18:10:38 ******/
SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO

/******************************************************************************
** Name: usp_Func_GetFuncByUserID
** Desc: 根据UserID获取用户权限
**
**
** Return Values:
**
** Parameters:
** Auth:
** Date:20018-03-06
*******************************************************************************/
CREATE PROC [dbo].[usp_Func_GetFuncByUserID]
(
@UserID UNIQUEIDENTIFIER = ‘B64A4EA9-972E-4252-BB79-62BD35D62D57‘
)
AS
BEGIN
WITH tree
AS ( SELECT DISTINCT
c.FuncID
FROM tbl_Base_UserRole AS b
INNER JOIN tbl_Base_RoleFunc AS c ON b.RoleID = c.RoleID
WHERE ( b.UserID = @UserID )
UNION ALL
--用户 组 权限
SELECT DISTINCT
ugfm.FuncID
FROM tbl_Base_UserGroupUserMapping ugm
INNER JOIN tbl_Base_UserGroupFuncMapping ugfm ON ugm.UserGroupID = ugfm.UserGroupID
WHERE ( ugm.UserID = @UserID )
UNION ALL
--用户 组 角色 权限
SELECT DISTINCT
ugfm.FuncID
FROM tbl_Base_UserGroupRoleMapping ugrm
INNER JOIN tbl_Base_UserGroupFuncMapping ugfm ON ugrm.UserGroupID = ugfm.UserGroupID
INNER JOIN tbl_Base_UserGroupUserMapping ugum ON ugum.UserGroupID = ugrm.UserGroupID
WHERE ugum.UserID = @UserID
-- 用户权限
UNION ALL
SELECT DISTINCT
ufm.FuncID
FROM tbl_Base_UserFuncMapping ufm
WHERE ufm.UserID = @UserID
)
SELECT DISTINCT
*
FROM tree
END

GO

调用存储过程:

USE [NewITMS]
GO

/****** Object: StoredProcedure [dbo].[usp_Menu_GetMenuByUserID] Script Date: 2018/3/6 18:12:33 ******/
SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO

/******************************************************************************
** Name: usp_Menu_GetMenuByUserID
** Desc: 根据UserID获取用户菜单
**
**
** Return Values:
**
** Parameters:
** Auth:
** Date:20018-03-06
*******************************************************************************/
CREATE proc [dbo].[usp_Menu_GetMenuByUserID]
@UserID UNIQUEIDENTIFIER =‘B64A4EA9-972E-4252-BB79-62BD35D62D57‘
as
begin

CREATE TABLE #tmp(
FuncID UNIQUEIDENTIFIER
)
INSERT INTO #tmp EXEC usp_Func_GetFuncByUserID @UserID

;--必要
WITH Tree --用户所有权限所对应的菜单(递归)(叶子节点+父亲节点)
AS ( SELECT a.MenuID ,
a.ParentMenuID ,
a.MenuName ,
a.FuncID ,
a.OrdinalNo
FROM tbl_Base_SysMenu AS a
INNER JOIN #tmp AS b_1 --用户所有权限
ON a.FuncID = b_1.FuncID
UNION ALL
SELECT e.MenuID ,
e.ParentMenuID ,
e.MenuName ,
e.FuncID ,
e.OrdinalNo
FROM tbl_Base_SysMenu AS e --用户所有权限所对应的菜单(递归)(叶子节点+父亲节点)
INNER JOIN Tree AS d --用户所有权限所对应的菜单(叶子节点)
ON e.MenuID = d.ParentMenuID
)
SELECT DISTINCT
CASE WHEN mt.menuID IS NULL THEN 0 --叶子节点
ELSE 1 --根节点
END MenuType ,
Tree_1.* ,
tbl_Base_Page.*
FROM ( SELECT FuncID ,
PageID ,
IsDefault
FROM tbl_Base_FuncPage
WHERE ( IsDefault = 1 )
) AS T --权限页面映射表
INNER JOIN tbl_Base_Page --页面表
ON T.PageID = tbl_Base_Page.PageID
RIGHT OUTER JOIN Tree AS Tree_1 --用户所有权限所对应的菜单(递归)(叶子节点+父亲节点)
ON T.FuncID = Tree_1.FuncID
LEFT JOIN tbl_Base_SysMenu mt --菜单表 用来确定菜单为根节点还是叶子节点
ON Tree_1.MenuID = mt.parentMenuID --菜单是否有子菜单

DROP TABLE #tmp
end

GO

原文地址:https://www.cnblogs.com/liuqiyun/p/8515971.html

时间: 2024-10-11 06:20:11

存储过程调用存储过程的相关文章

Oracle存储过程调用存储过程

今天突然突发奇想让一个存储过程调用另外一个存储过程返回的游标,一个自己写的demo 内存储过程(v_id为传入的参数,result_cursor为传出的存储过程,放在cursor_package中) create or replace procedure proc_innercursor(v_id in varchar, result_cursor out cursor_package.type_cursor) isv_name varchar2(10);begin open result_cu

Java数据库连接——JDBC调用存储过程,事务管理和高级应用

阅读目录 一.JDBC常用的API深入详解及存储过程的调用1.存储过程(Stored Procedure)的介绍2.JDBC调用无参存储过程3.JDBC调用含输入参数存储过程4.JDBC调用含输出参数存储过程二.JDBC的事务管理1.JDBC实现事务管理2.通过代码实现事物的管理三.数据库连接池(dbcp.c3p0)1.dbcp使用步骤2.c3p0使用步骤3.连接池总结四.JDBC的替代产品(Hibernate.Mybatis)1.Commons-dbutils 2.Hibernate简介3.M

08_调用存储过程

1 需求 查询得到男性或女性的数量, 如果传入的是0就女性否则是男性 2 准备数据表和存储过程 2.1 表及数据 create table p_user( id int primary key auto_increment, name varchar(10), sex char(2) ); insert into p_user(name,sex) values('A',"男"); insert into p_user(name,sex) values('B',"女"

JDBC【PreparedStatment、批处理、处理二进制、自动主键、调用存储过程、函数】

1.PreparedStatement对象 PreparedStatement对象继承Statement对象,它比Statement对象更强大,使用起来更简单 Statement对象编译SQL语句时,如果SQL语句有变量,就需要使用分隔符来隔开,如果变量非常多,就会使SQL变得非常复杂.PreparedStatement可以使用占位符,简化sql的编写 Statement会频繁编译SQL.PreparedStatement可对SQL进行预编译,提高效率,预编译的SQL存储在PreparedSta

MyBatis入门学习教程-调用存储过程

一.提出需求 查询得到男性或女性的数量, 如果传入的是0就女性否则是男性 二.准备数据库表和存储过程 1 create table p_user( 2 id int primary key auto_increment, 3 name varchar(10), 4 sex char(2) 5 ); 6 7 insert into p_user(name,sex) values('A',"男"); 8 insert into p_user(name,sex) values('B',&qu

导入Excel用户表,调用存储过程

花了一天半的时间学习了一下导入Excel用户表,调用存储过程,主要是学习存储过程.因为之前没有具体在项目中应用过. 这里我们采用导入Excel到临时表,然后存储过程中读取临时表判断数据类型和数据格式,然后保存到正式表. 导入Excel采用spring 的POI技术. 本文内容较多,请选择性阅读. controller里面的代码: /**  * Excel导入用户表,调用存储过程,先导入临时表,再在存储过程中判断,判断通过后导入正式表,错误的则记录错误日志表中. lijianbo  *   * @

FAQ系列 | Spring框架中调用存储过程失败

Spring框架中,调用存储过程同时还需要show create procedure权限,对于普通用户而言,还要授予 select on mysql.proc 权限才能正常 --------------------------------------分割线-------------------------------------- 知数堂 (http://zhishuedu.com)培训是由资深MySQL专家叶金荣.吴炳锡联合推出的专业优质培训品牌,主要有MySQL DBA实战优化和Python

jdbc中的Statement对象和Preparedstatement对象的区别,以及通过jdbc操作调用存储过程

一. java.sql.*   和  javax.sql.*的包的类结构 |- Driver接口: 表示java驱动程序接口.所有的具体的数据库厂商要来实现此接口. |- connect(url, properties):  连接数据库的方法. url: 连接数据库的URL URL语法: jdbc协议:数据库子协议://主机:端口/数据库 user: 数据库的用户名 password: 数据库用户密码 |- DriverManager类: 驱动管理器类,用于管理所有注册的驱动程序 |-regis

mybatis调用存储过程

最近在研究mybatis调用存储过程,发表一下自己的学习心得 其中最好用的就是通过map传值,结果还用这个map接收,因为map是一个非常强大的东西,有时候存储过程要操作多张表. 比如说:往多张表插入数据,用JavaBean的方式就很难做到,参数对应多个实体类不好解决,用map就能完美的解决这个问题. Map<String, Object> map=new HashMap<String, Object>把需要的参数往里面一放,就能很容易解决问题 dao层(dao接口),在dao接口