在不使用动态 SQL 的情况下更新从文件系统获取文件的二进制字段

Updating a binary field taking a file from filesystem without using dynamic SQL

场景

我在 Sql Server 2005 中有一个 table(我们称之为 myTable),其中包含一些列,包括一个 varbinary(max) 字段:

我经常需要通过 TSQL 脚本从文件系统读取文件来更新包含在 varbinary(max) 列中的文件。这些脚本在 Sql Server Management Studio 中执行。

我编写了以下脚本来使用 OPENROWSET 更新二进制值:

begin try
    begin tran
    update myOtherTable set field1 = 'value1'
    --other instructions
    --...

    UPDATE myTable 
    SET [REPORT_FILE] = (SELECT * FROM OPENROWSET(BULK 'c:\filename.ext', SINGLE_BLOB) AS T)
    WHERE REPORT_ID = ...
end try

begin catch
    if @@TRANCOUNT > 0 begin
        rollback tran
        --other instructions for error handling
        --...
    end
end catch

if @@TRANCOUNT > 0  begin
    commit tran
end 

问题

我想处理文件丢失或者文件名错误的情况;期望的行为是:

如果输入文件丢失,上述脚本会产生错误,但 CATCH 块无法捕获异常,因此交易和对 myOtherTable 的更新仍处于挂起状态,因为 COMMIT 指令未执行。结果我不得不手动回滚事务。

我的解决方案

我发现捕获 CATCH 块中的错误的唯一方法是使用动态 TSQL,所以我的实际脚本是:

declare @dSQL nvarchar(max)

begin try
    begin tran
        update myOtherTable set field1 = 'value1'
        --other instructions 
        --...
        set @dSQL = '
            UPDATE myTable 
            SET [REPORT_FILE] = (SELECT * FROM OPENROWSET(BULK ''c:\filename.ext'', SINGLE_BLOB) AS T)
            WHERE REPORT_ID = ...
             '
    exec sp_executesql @dSQL
end try

begin catch
    if @@TRANCOUNT > 0 begin
        rollback tran
        --other instructions for error handling
        --...
    end
end catch

if @@TRANCOUNT > 0  begin
    commit tran
end

问题

是否可以在不使用动态 TSQL 的情况下实现所需的行为?

最好先检查文件是否存在。

DECLARE @isExists INT;
EXEC master.dbo.xp_fileexist 'C:\filename.ext', @isExists OUTPUT

--If the file exists, then 
IF(@isExists = 1)
BEGIN
    SELECT 'It exists!'
    --Do your work here
END
ELSE
BEGIN
    --Return some kind of error message
    SELECT 'File does not exist.'
END