我想创建一个函数来返回目录中的文件列表,以便我可以在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'
但是将它们组合起来不是。
关于另一种方法的任何建议。
答案 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过滤器而不是标准*
和?
通配符。但是,仅供参考:它仅在完整版中提供,而不是在免费版中。