我们可以在另一个存储过程中编写子函数或过程

时间:2009-01-30 14:37:41

标签: sql sql-server-2005

我想检查SQL Server(2000/05/08)是否具有编写嵌套存储过程的能力,我的意思是 - 在另一个存储过程中编写子函数/过程。不要叫另一个SP。

为什么我在考虑它是 - 我的一个SP有重复的代码行,并且仅针对此SP.So如果我们有这个嵌套的SP功能,那么我可以在我的内部声明另一个子/本地程序主SP并将所有重复行放入其中。我可以在我的主SP中调用本地sp。我记得Oracle SP中提供了这样的功能。

如果SQL服务器也具有此功能,有人可以解释一些有关它的更多详细信息,或提供我可以找到文档的链接。

提前致谢 西

10 个答案:

答案 0 :(得分:5)

我不建议这样做,因为每次创建时都必须计算新的执行计划,但是肯定可以完成(一切皆有可能,但并不总是建议)。

以下是一个例子:

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

答案 1 :(得分:4)

它没有这个功能。除了阻止嵌套SPROC中的代码从其他地方调用之外,很难看出这样的功能会带来什么样的真正好处。

答案 2 :(得分:4)

Oracle的PL / SQL是一种特殊情况,是一种严重基于Ada的语言,而不是简单的DML,其中包含一些程序结构。您是否认为这是一个好主意可能取决于您对DBMS中程序代码的偏好以及您对学习复杂新语言的喜好。

根据我的经验(Oracle,MS SQL,Sybase,MySQL,SQLite),子程序减少重复或其他方面的想法在很大程度上与其他数据库平台不同。

虽然SQL构建过程可行,但我认为John建议你不要使用他的正确答案!

你没有说出你的重复线条采用什么形式,所以我将提供三种可能的选择,从最简单的开始:

  1. 什么都不做。接受程序性 SQL是一种缺乏原始语言 这么多“基本”结构 你根本不会使用它 不是唯一的选择。

  2. 将程序操作移到DBMS之外,并在用更复杂的语言编写的代码中执行它们。考虑如何调整架构以从数据存储平台中提取业务逻辑(嘿,为什么不重新设计整个事物!)

  3. 如果重复发生在DML中,特别是SELECT,请考虑引入视图以减少查询。

  4. 编写代码以生成存储过程,作为构建过程的一部分。这样,如果重复的行需要更改,您可以在一个地方更改它们并自动生成重复。

  5. 那是four。在我打字的时候,我想到了另一个;认为这是奖金。

答案 3 :(得分:4)

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;

我们在这里做的是创建一个过程,该过程在连接的生命周期中存在,然后用于将一些数据插入表中。

答案 4 :(得分:3)

John的sp_helloworld确实有效,但这就是你不经常看到这种情况的原因。

编译存储过程时会产生非常大的性能影响。有一篇关于解决由大量重新编译引起的性能问题的微软文章,因为这会让你的系统速度下降很多:

http://support.microsoft.com/kb/243586

您最好只使用要调用的T-SQL创建字符串变量,然后重复执行该字符串变量,而不是创建存储过程。

不要误解我的意思 - 这也是一个非常糟糕的性能想法,但它比在运行中创建存储过程更好。如果您可以将此代码保存在永久存储过程或函数中并消除重新编译延迟,则SQL Server可以为代码构建一次执行计划,然后非常快速地重用该计划。

答案 5 :(得分:3)

我在SQL触发器中遇到了类似的情况(类似于SQL过程),其中我基本上具有相同的insert语句,对于由1个事件导致的13个可能的键值,最多执行13次。我使用了一个计数器,使用DO WHILE将其循环13次,并使用CASE进行每个键值处理,同时保留一个标记以确定何时需要插入以及何时跳过。

答案 6 :(得分:2)

如果MS除了GOTO之外开发GOSUB,那将是非常好的,这是一件容易的事情!

为“内部例程”polute对象结构创建过程或函数。

我像这样“实施”它

BODY1:

转到HEADER HEADER_RET1:

insert into body ...

goto BODY1_RET

BODY2:

转到HEADER HEADER_RET2:

INSERT INTO body....

goto BODY2_RET

HEADER:

insert into header

if @fork=1 goto HEADER_RET1

if @fork=2 goto HEADER_RET2

select 1/0 --flow check!

答案 7 :(得分:2)

我也需要这个。我有两个函数可以将案例计数带回到存储过程,它会拉出所有用户的列表,以及它们的案例数量。

沿着

的路线
select name, userID, fnCaseCount(userID), fnRefCount(UserID)
  from table1 t1
  left join table2 t2
    on t1.userID = t2.UserID

对于一个相对较小的集合(400个用户),它一次调用这两个函数中的每一个。总共,该800从存储过程中调出。不是很漂亮,但是人们不希望sql server在少数几个调用中遇到问题。

这需要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秒。我会继续玩它。

答案 8 :(得分:1)

我同意andynormancx这样做似乎没什么意义。

如果你真的希望共享代码包含在SP中,那么你可以用GOTO或动态SQL来拼凑一些东西,但是使用单独的SP或UDF正确地执行它几乎在所有方面都会更好

答案 9 :(得分:0)

谢谢大家的回复! 我最好再创建一个带有重复代码的SP并调用它,这是性能和看起来很明智的最佳方式。