如何使用SQL验证Windows中是否存在文件?

时间:2011-07-06 16:25:30

标签: sql sql-server

我在Windows Server上运行了一个SQL Server,并且在表的特定列中,我有一个Zip文件的路径(后者又有数据源存储在数据库中)。其中一些无效(与数据库中的数据不匹配)。我需要让SQL Server验证这些Zip文件是否存在,以及它们是否与存储zip文件的路径和名称的列相匹配。这样我就会删除错误的文件路径列对应关系。

2 个答案:

答案 0 :(得分:7)

你可以使用未记录的proc xp_fileexist如果存在则返回1,否则返回0

SET NOCOUNT ON
DECLARE @iFileExists INT

EXEC master..xp_fileexist 'c:\bla.txt', 
 @iFileExists OUTPUT

select @iFileExists

答案 1 :(得分:2)

您可以使用xp_fileexist但请注意它没有记录且不受支持。

某些人可以使用SQLCLR,但是您没有指定您正在使用的SQL Server版本,因此它可能不相关 - 并且在任何情况下都默认禁用它,并且安全策略阻止其在某些版本中使用地方。

您可以使用#temp表和xp_cmdshell,但是xp_cmdshell通常会被禁用,原因与SQLCLR相同。

/* if you need to enable xp_cmdshell:

exec master..sp_configure 'show adv', 1;
reconfigure with override;
exec master..sp_configure 'xp_cmdshell', 1;
reconfigure with override;
exec master..sp_configure 'show adv', 0;
reconfigure with override;

*/

SET NOCOUNT ON;

DECLARE 
   @file VARCHAR(1000),
   @path VARCHAR(255),
   @cmd  VARCHAR(2048);

SELECT
   @file = 'foo.zip',
   @path = 'C:\wherever\';

SELECT @cmd = 'dir /b "' + @path + @file + '"';

CREATE TABLE #x(a VARCHAR(1255));
INSERT #x EXEC master..xp_cmdshell @cmd;
IF EXISTS (SELECT 1 FROM #x WHERE a = @file)
   PRINT 'file exists';
ELSE
   PRINT 'file does not exist';
DROP TABLE #x;
根据新要求

编辑。它显示表或数据库中的文件列表,并指示文件是仅位于一个位置还是两者都存在。它假设路径+文件长度<= 900个字符(只是为了能够在至少一侧使用索引)。

USE tempdb;
GO

CREATE TABLE dbo.files(f VARCHAR(1000));

INSERT dbo.files(f) SELECT 'zip_that_does_not_exist.zip'
    UNION ALL SELECT 'c:\path\file_that_does_not_exist.zip'
    UNION ALL SELECT 'c:\path\file_that_exists.zip'
    UNION ALL SELECT 'zip_that_exists.zip';

DECLARE 
   @path VARCHAR(255),
   @cmd  VARCHAR(2048);

SELECT
   @path = path_column,
   @cmd  = 'dir /b "' + path_column + '"'
FROM 
   dbo.table_that_holds_path;

CREATE TABLE #x(f VARCHAR(900) UNIQUE);

INSERT #x EXEC master..xp_cmdshell @cmd;
DELETE #x WHERE f IS NULL;
UPDATE #x SET f = LOWER(f);

WITH f AS 
(
    SELECT f = REPLACE(LOWER(f), LOWER(@path), '')
        FROM dbo.files
)
SELECT 
    [file] = COALESCE(x.f, f.f),
    [status] = CASE 
        WHEN x.f IS NULL THEN 'in database, not in folder'
        WHEN f.f IS NULL THEN 'in folder, not in database'
        ELSE 'in both' END
FROM
    f FULL OUTER JOIN #x AS x
    ON x.f = f.f;

DROP TABLE #x, dbo.files;