我想检查SQL Server(2000/05/08)是否具有编写嵌套存储过程的能力,我的意思是 - 在另一个存储过程中编写子函数/过程。不要叫另一个SP。
为什么我在考虑它是 - 我的一个SP有重复的代码行,并且只针对此SP.So如果我们有这个嵌套的SP功能,那么我可以在我的主SP中声明另一个子/本地程序把所有重复的行放在那里。我可以在我的主SP中调用本地sp。我记得Oracle SP中提供了这样的功能。
如果SQL服务器也具有此功能,有人可以解释一些有关它的更多详细信息或提供我可以找到文档的链接。
在此先感谢赛
我不建议这样做,因为每次创建时都必须计算新的执行计划,但是肯定可以完成(一切皆有可能,但并不总是建议)。
这是一个例子:
CREATE PROC [dbo].[sp_helloworld]
AS
BEGIN
SELECT 'Hello World'
DECLARE @sSQL VARCHAR(1000)
SET @sSQL = 'CREATE PROC [dbo].[sp_helloworld2]
AS
BEGIN
SELECT ''Hello World 2''
END'
EXEC (@sSQL)
EXEC [sp_helloworld2];
DROP PROC [sp_helloworld2];
END
你会得到警告
The module 'sp_helloworld' depends on the missing object 'sp_helloworld2'.
The module will still be created; however, it cannot run successfully until
the object exists.
您可以使用上面的EXEC('sp_helloworld2')绕过此警告。
但如果你打电话给EXEC [sp_helloworld],你会得到结果
Hello World
Hello World 2
谢谢大家的回复!我最好再创建一个带有重复代码的SP并调用它,这是性能和看起来明智的最佳方式。
它没有这个功能。除了阻止嵌套SPROC中的代码从其他地方调用之外,很难看出这样的功能会带来什么样的真正好处。
Oracle的PL / SQL是一种特殊情况,是一种严重基于Ada的语言,而不是简单的DML,其中包含一些程序结构。您是否认为这是一个好主意可能取决于您对DBMS中程序代码的偏好以及您对学习复杂新语言的喜好。
根据我的经验(Oracle,MS SQL,Sybase,MySQL,SQLite),子程序减少重复或其他方面的想法在很大程度上与其他数据库平台不同。
虽然SQL构建过程可行,但我认为John建议你不要使用他的正确答案!
你没有说出你的重复行采用什么形式,所以我将提供三种可能的替代方案,从最简单的方法开始:
那是four。在我打字的时候,我想到了另一个;认为这是一个奖金。
CREATE TABLE #t1 (digit INT, name NVARCHAR(10));
GO
CREATE PROCEDURE #insert_to_t1
(
@digit INT
, @name NVARCHAR(10)
)
AS
BEGIN
merge #t1 AS tgt
using (SELECT @digit, @name) AS src (digit,name)
ON (tgt.digit = src.digit)
WHEN matched THEN
UPDATE SET name = src.name
WHEN NOT matched THEN
INSERT (digit,name) VALUES (src.digit,src.name);
END;
GO
EXEC #insert_to_t1 1,'One';
EXEC #insert_to_t1 2,'Two';
EXEC #insert_to_t1 3,'Three';
EXEC #insert_to_t1 4,'Not Four';
EXEC #insert_to_t1 4,'Four'; --update previous record!
SELECT * FROM #t1;
我们在这里做的是创建一个过程,该过程在连接的生命周期中存在,然后用于将一些数据插入表中。
约翰的sp_helloworld确实有效,但这就是你不经常看到这种情况的原因。
编译存储过程时会产生非常大的性能影响。有一篇关于解决由大量重新编译引起的性能问题的微软文章,因为这会让你的系统速度下降很多:
http://support.microsoft.com/kb/243586
您最好只使用要调用的T-SQL创建字符串变量,然后重复执行该字符串变量,而不是创建存储过程。
不要误解我的意思 - 这也是一个非常糟糕的性能想法,但它比在运行中创建存储过程更好。如果您可以将此代码保留在永久存储过程或函数中并消除重新编译延迟,则SQL Server可以为代码构建一次执行计划,然后非常快速地重用该计划。
我在SQL触发器中遇到了类似的情况(类似于SQL过程),其中我基本上有相同的insert语句,对于13个可能的键值导致1次事件最多执行13次。我使用了一个计数器,使用DO WHILE将其循环13次,并使用CASE进行每个键值处理,同时保留一个标志以确定何时需要插入以及何时跳过。
我也需要这个。我有两个函数可以将案例计数带回到存储过程,它会拉出所有用户的列表,以及它们的案例数量。
沿着这条路线
select name, userID, fnCaseCount(userID), fnRefCount(UserID)
from table1 t1
left join table2 t2
on t1.userID = t2.UserID
对于一个相对较小的集合(400个用户),它一次调用这两个函数中的每一个。总共有800个来自存储过程的调用。不是很漂亮,但人们不希望sql服务器出现这么少的调用问题。
这需要4分钟才能完成。
单独地,函数调用几乎是瞬时的。甚至800个近乎即时的呼叫应该几乎是瞬时的。
所有索引都已就绪,SSMS建议在分析存储过程和函数的执行计划时没有新的索引。
我从函数中复制了代码,并将其放入存储过程中的SQL查询中。但似乎sp和函数之间的过渡是时间的消耗。
执行时间在18秒时仍然太高,但允许查询在我们的30秒超时窗口内完成。
如果我可以有一个子程序,它会使代码更漂亮,但仍然可能增加了开销。
我可能接下来尝试将相同的功能移动到我可以在连接中使用的视图中。
select t1.UserID, t2.name, v1.CaseCount, v2.RefCount
from table1 t1
left join table2 t2
on t1.userID = t2.UserID
left join vwCaseCount v1
on v1.UserID = t1.UserID
left join vwRefCount v2
on v2.UserID = t1.UserID
好的,我刚刚从函数中创建了视图,因此我的执行时间从4分钟到18秒再到8秒。我会继续玩它。
如果MS除了GOTO之外开发GOSUB,那将是非常好的,这是一件容易的事!
为“内部例程”创建过程或函数,以便对象结构进行轮询。
我像这样“实施”它
BODY1:
转到HEADER HEADER_RET1:
insert into body ...
goto BODY1_RET
BODY2:
转到HEADER HEADER_RET2:
INSERT INTO body....
goto BODY2_RET
标头:
insert into header
if @fork=1 goto HEADER_RET1
if @fork=2 goto HEADER_RET2
select 1/0 --flow check!
我同意andynormancx这样做似乎没有多大意义。
如果你真的希望共享代码包含在SP中,那么你可以用GOTO或动态SQL来拼凑一些东西,但是使用单独的SP或UDF正确地执行它几乎在所有方面都会更好。