我有一个存储过程引发错误的问题,因为它试图在其中运行/验证OPENROWSET
它实际上不必执行的查询。
看起来像这样的存储过程:
IF (@flagA = 1)
BEGIN
INSERT INTO #tmpData(Column1, Column2, Column3)
SELECT A, B, C
FROM (
SELECT *
FROM OPENROWSET(
'Microsoft.ACE.OLEDB.12.0',
'Text; HDR=Yes; Database=\\server\tmpFiles',
'SELECT * FROM FileA.txt')
) as T
END
IF (@flagB = 1)
BEGIN
INSERT INTO #tmpData(Column1, Column2, Column3)
SELECT D, E, F
FROM (
SELECT *
FROM OPENROWSET('Microsoft.Ace.OLEDB.12.0',
'Excel 8.0;Database=\\server\tmpFiles\FileB.xls',
'SELECT * FROM [Sheet$]')
) as T
END
IF (@flagC = 1)
BEGIN
INSERT INTO #tmpData(Column1, Column2, Column3)
SELECT G, H, I
FROM (
SELECT *
FROM OPENROWSET('Microsoft.Ace.OLEDB.12.0',
'Excel 8.0;Database=\\server\tmpFiles\FileC.xls',
'SELECT * FROM [Sheet1$]')
) as T
END
请注意,每个OPENROWSET
文件都以不同的格式引用具有不同列名的不同文件。
我的问题是,如果其中一个文件不存在,或者以错误的格式存在(例如有人错误地将 FileB 上传为 FileC),即使该OPENROWSET
查询永远不会在该过程尝试运行时出现错误意味着被执行。
例如,如果 FileB 不存在并且您尝试使用 运行该过程@flagB = 0
,它将抛出一个错误,说它找不到链接服务器FileB
或者,如果用户错误地将 a 上传FileB
为 a FileC
,然后通过从表单中删除来纠正自己FileC
,它会在下次运行过程时抛出错误Cannot process the object "SELECT * FROM [Sheet1$]"
,因为 FileC 不会有一个名为 的工作表Sheet1
,即使@flagC = 0
OPENROWSET
如果查询不是被执行的,我如何防止 SQL 验证查询?
有几个选项可用。其中之一是为您的插入调用使用动态 SQL。这样,在执行发生之前,验证实际上不会发生。对于您的示例,它可能如下所示:
在这种情况下,验证直到运行时才会发生。缺点是故障排除变得更加困难,因为您现在正在尝试调试动态 SQL。
您还可以将几个单独的语句合并为一个。
第二种选择是将调用拆分为单独的过程。我会把它放在遥远的第二位,主要是因为它很容易滥用它并开始假装 T-SQL 存储过程等同于 C 风格的方法,而忘记了可能存在显着的性能差异。无论如何,将 INSERT 语句移动到三个单独的过程中并传入任何必要的参数,如下所示:
您无法使用临时表执行此操作,因此除非您有永久“临时”表可用(或使用全局临时表),否则可能会丢弃此选项。
如果您确实想使用临时表,可以将 exec 语句更改为
insert into #tmpData exec InsertFlagA @parms1
.