我知道这个问题已经问了很多次,也知道为什么SQL Server不允许这样做。
但有没有任何解决方法,除了使用扩展存储过程之外?
请不要告诉我将我的函数转换为存储过程……
所以我真正想问的是:有没有任何方法可以从函数内运行存储过程?
编辑:
证明了一点:有一种方法可以绕过它,但它非常错误,我不会这样做。我将把它更改为存储过程,并在其他地方执行。
我知道这个问题已经问了很多次,也知道为什么SQL Server不允许这样做。
但有没有任何解决方法,除了使用扩展存储过程之外?
请不要告诉我将我的函数转换为存储过程……
所以我真正想问的是:有没有任何方法可以从函数内运行存储过程?
编辑:
证明了一点:有一种方法可以绕过它,但它非常错误,我不会这样做。我将把它更改为存储过程,并在其他地方执行。
编辑:我没有尝试过这个方法,所以不能保证效果!而且你已经知道不应该这样做,所以请不要这样做。但是...
试一下在这里找: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
函数不允许具有副作用,如改变表内容。
储存过程是允许的。
如果函数调用了储存过程,则该函数将能够具有副作用。
所以,很抱歉,您不能从函数中调用存储过程。
SET @Variable = function
,或者可能由于作为查询的一部分而运行多次,即使它只返回单个行)。此外,“如果一个函数调用了存储过程,那么函数就能够产生副作用”也不是真的,因为 SQL Server 可以防止那些被禁止的操作,就像从 SQLCLR 函数调用存储过程时所做的那样。 - Solomon RutzkySET @Variable = function();
语句或SELECT * FROM function();
查询中使用它,则应该没问题。CREATE PROCEDURE [dbo].[usp_FunctionBuilder]
DECLARE @outerSql VARCHAR(MAX)
DECLARE @innerSql VARCHAR(MAX)
2. 在您的函数中构建要执行的动态 SQL(例如:您可以使用循环和联合,读取另一个存储过程,使用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、动态服务器/数据库/表名、循环等。
您需要根据自己的需求进行调整(例如更改函数中的返回值)。
这里还有另一种可能的解决方案:
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
那样可怕,但在实际使用中也有太多的含义。
xp_cmdshell
调用osql(实际上应该是SQLCMD)要好得多。 - Solomon Rutzky