TSQL - 从函数返回存储过程的结果

时间:2016-03-17 00:54:23

标签: sql sql-server function tsql stored-procedures

我想创建一个函数来返回目录中的文件列表,以便我可以在preg_replace_callback语句中调用该函数。是的我可以使用存储过程,但是我需要使用游标。

这就是我想要做的,但这会给出错误

  

无效使用副作用操作符' INSERT EXEC'在一个函数内。

代码:

SELECT

有趣的是,这是有效的:

CREATE FUNCTION [dbo].[fnGetFilesInDirectory] 
     (@Path VARCHAR(512), 
      @FileMask VARCHAR(256))
RETURNS @Files TABLE (
    FilePath VARCHAR(512)
)
AS
BEGIN
    DECLARE @Cmd VARCHAR(8000)  
    SET @cmd = 'dir ' + quotename(@Path + @FileMask, NCHAR(34)) + ' /B' 

    INSERT INTO @Files (FilePath)
    EXEC xp_cmdshell @cmd

    RETURN 
END

这在没有INSERT之前有效:

INSERT INTO @Files (FilePath) SELECT 'test.txt'

但是将它们组合起来不是。

关于另一种方法的任何建议。

2 个答案:

答案 0 :(得分:3)

documentation明确指出这是不可能的:

  

从函数调用扩展存储过程

     

扩展存储过程,从内部调用时   函数,不能将结果集返回给客户端。任何ODS API   将结果集返回给客户端将返回FAIL。扩展存储   过程可以连接回SQL Server实例;但是,它   不应该尝试加入与该函数相同的事务   调用了扩展存储过程。

我不确定这种限制来自何处。建议的解决方法是一个黑客,但它可能会工作。调用执行shell脚本的扩展存储过程,该脚本连接到使用shell命令的结果填充表的数据库到另一个表中。使用该表的结果。可能存在一些交易问题。

我不完全理解将此逻辑放入函数中的优势。我承认这似乎很方便。但是,如果您正在迭代文件 - 比如加载它们 - 那么您需要在每个文件上执行存储过程。如果要加载表,可以使用相同的逻辑通过存储过程完成。

答案 1 :(得分:0)

问题几乎可以肯定是SELECT构造创建了一个内部事务,并且你不允许在T-SQL函数中使用事务(标量UDF和多语句TVF;内联TVF不是&# 39;与此相关,因为它只能是FileSystemInfo语句。

然而,通过SQLCLR TVF处理这一点非常简单。您可以使用DirectoryInfo*等类来以几种不同的方式枚举目录中的文件(即有或没有传递可包含?和{{1的过滤器的过滤器通配符,通过子目录递归或不通过)。您只需将程序集标记为WITH PERMISSION_SET = EXTERNAL_ACCESS即可。而你需要(或想要)将数据库设置为TRUSTWORTHY ON,而是签署程序集,从签名的程序集中创建[master]中的非对称密钥,创建一个从该非对称密钥登录,然后授予该登录EXTERNAL ACCESS ASSEMBLY权限。有关使用SQLCLR的更多信息,请参阅我在SQL Server Central上撰写的关于该主题的系列:Stairway to SQLCLR(该站点确实需要免费注册,但它绝对值得)。特别是级别7显示了在使用Visual Studio / SSDT时如何正确处理安全性。

对于那些不想进行任何开发的人,我编写了一个SQLCLR函数库和名为SQL#的存储过程,其中包含多个文件系统函数,包括 File_GetDirectoryListing 这正是这个。它是一个流媒体TVF,所以它非常快/高效,并且允许在文件名和路径上使用RegEx过滤器而不是标准*?通配符。但是,仅供参考:它仅在完整版中提供,而不是在免费版中。