从函数执行存储过程

问题描述 投票:43回答:5

我知道这已被要求死亡,我知道为什么SQL Server不允许你这样做。

但除了使用扩展存储过程之外,还有其他解决方法吗?

请不要告诉我将我的功能转换为程序...

所以我真正要问的是:有没有办法从函数中运行存储过程?

编辑:

有点证明:有一种解决方法,但它是如此错误,我不会这样做。我要将其更改为存储过程并在其他地方执行。

sql sql-server sql-server-2005 stored-procedures user-defined-functions
5个回答
26
投票

编辑:我没试过这个,所以我不能保证!你已经知道你不应该这样做,所以请不要这样做。但...

试试这里:http://sqlblog.com/blogs/denis_gobo/archive/2008/05/08/6703.aspx

关键位是我试图为您的目的调整的位:

DECLARE @SQL varchar(500)

SELECT @SQL = 'osql -S' +@@servername +' -E -q "exec dbName..sprocName "'

EXEC master..xp_cmdshell @SQL

11
投票

不允许函数产生副作用,例如改变表格内容。

存储过程是。

如果一个函数称为存储过程,该函数将变得能够产生副作用。

所以,抱歉,但不,你不能从函数调用存储过程。


1
投票

除了使用OPENQUERY和xp_cmdshell之外,另一个选项是使用SQLCLR(SQL Server的“CLR集成”功能)。 SQLCLR选项不仅比其他两种方法更安全,而且还有一个潜在的好处是能够在当前会话中调用存储过程,以便它可以访问任何基于会话的对象或设置,例如:

  • 临时表
  • 临时存储过程
  • CONTEXT_INFO

这可以通过使用“context connection = true;”来实现。作为ConnectionString。请记住,将强制执行对T-SQL用户定义函数的所有其他限制(即不能产生任何副作用)。

如果您使用常规连接(即不使用上下文连接),那么它将作为独立调用运行,就像使用OPENQUERY和xp_cmdshell方法时一样。

但是,请记住,如果您将在一个影响多于一行的语句中使用调用存储过程的函数(无论您使用哪三种方法),那么该行为不能指望运行一次每排。正如@MartinSmith在对@MatBailie的回答的评论中提到的那样,查询优化器不保证函数执行的时间或次数。但是如果你在SET @Variable = function();语句或SELECT * FROM function();查询中使用它,那么它应该没问题。

下面的文章(我写的)中显示了使用.NET / C#SQLCLR用户定义函数执行存储过程的示例:

Stairway to SQLCLR Level 2: Sample Stored Procedure and Function


0
投票

这是另一种可能的解决方法:

if exists (select * from master..sysservers where srvname = 'loopback')
    exec sp_dropserver 'loopback'
go
exec sp_addlinkedserver @server = N'loopback', @srvproduct = N'', @provider = N'SQLOLEDB', @datasrc = @@servername
go

create function testit()
    returns int
as
begin
    declare @res int;
    select @res=count(*) from openquery(loopback, 'exec sp_who');
    return @res
end
go

select dbo.testit()

它不像xp_cmdshell那么可怕,但也有too many implications实用。


0
投票

我找到了解决这个问题的方法。我们可以在存储过程中使用“呈现的”sql构建一个Function或View,然后可以正常执行。

1.创造另一个sproc

CREATE PROCEDURE [dbo].[usp_FunctionBuilder]
DECLARE @outerSql VARCHAR(MAX)
DECLARE @innerSql VARCHAR(MAX)

2.在你的函数中构建你想要执行的动态sql(例如:你可以使用循环和联合,你可以在另一个sproc中读取,使用if语句和参数用于条件sql等)

SET @innerSql = 'your sql'

3.将@innerSql包含在create function语句中,并定义在@innerSql中使用的所有外部参数,以便将它们传递给生成的函数。

SET @outerSql = 'CREATE FUNCTION [dbo].[fn_GeneratedFunction] ( @Param varchar(10))
RETURNS TABLE
AS
RETURN
' + @innerSql;


EXEC(@outerSql)

这只是伪代码,但该解决方案解决了许多问题,例如链接服务器限制,参数,函数中的动态sql,动态服务器/数据库/表名,循环等。

您需要根据需要调整它(例如:更改函数中的返回值)

© www.soinside.com 2019 - 2024. All rights reserved.