1. 程式人生 > >存儲過程調用存儲過程

存儲過程調用存儲過程

sta err menu 根據 cnblogs tin reat mapping urn

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

存儲過程調用存儲過程