1

我正在MERGE针对 SQL Server 2008 R2 数据库(处于 2008 兼容模式)运行语句。

确切的合并语句 SQL 无关紧要,但这里是 MERGE 语句的示例:

MERGE Users
USING (VALUES 
('{77410DC5-7A3E-4F1A-82C6-8EFB3068DE66}')
) AS rows(UserGUID)
ON Users.UserName = rows.UserName
WHEN NOT MATCHED BY SOURCE THEN
DELETE; --always end MERGE with semi-colon

从 SSMS 或运行 Windows 7 的客户端 PC 执行此语句时,它会正确执行。

但是,当我的软件在 Windows XP 或 Windows Server 2003 R2 的客户端 PC 上运行时,sqlCommandText在到达服务器之前被更改。在 SQL Server Profiler 中,我可以看到正在执行的 SQL 是:

exec MERGE Users
USING (VALUES 
('{77410DC5-7A3E-4F1A-82C6-8EFB3068DE66}')
) AS rows(UserGUID)
ON Users.UserName = rows.UserName
WHEN NOT MATCHED BY SOURCE THEN
DELETE; --always end MERGE with semi-colon

哪个不是有效的 SQL,SQL Server 会抛出错误:

Incorrect syntax near the keyword 'MERGE'

您可以通过尝试对 SQL Server 2008 R2 数据库执行它来确认它是无效的 SQL。

Peter Boulton 在 Microsoft 论坛上报告了同样的问题:

SQL MERGE 语法适用于 Win7 SP1 客户端,但在早期平台上失败

我相信 ADO 在将 SQL 发送到服务器之前会对其进行解析。针对 Win7 SP1 和 WinServer 2008 R2 更新了数据访问组件。但是,我相信 XP SP3 的数据访问组件早于 SQL Server 2008。

这就是 SQL 在 Win7 SP1 上工作但在 XP 上不行的原因。

的“解决方案”是将 SQL 包装在一个中,EXEC以便 ADO 允许它通过,如下所示:

EXEC('合并....等')

他的技巧当然有效,改变:

MERGE Users ...

进入

EXEC('MERGE Users' ...)

但我想提出真正的解决方案。我不知道链中的谁负责更改我的命令文本:

ADO -> OLEDB -> SQLOLEDB -> SQL Server

但我希望他们停下来。

我如何通过 ADO 指定我的命令文本,并且让 SQLOLEDB 不修改它?

现在我的代码是1

String sqlCommandText = "MERGE Users" //snip;
int recordsAffected;

connection.Execute(
    sqlCommandText, 
    out recordsAffected, 
    adCmdText | adExecuteNoRecords);

我没有看到任何ExecuteOptionEnum,或者CommandTypeEnum告诉 ADO 和底层提供者,将文本视为原始的。


现在修复黑客是:

sql = "MERGE Users" ...

ExecuteNoRecords(connection, sql);

使用修改后的助手:

int ExecuteNoRecords(Connection connection, String sql)
{
   //20130611: Fix bug in ADO that mangles/breaks SQL it doesn't understand (e.g. MERGE on Windows XP)
   String obfuscatedCommandText = 'EXEC(' + QuotedStr(sql)+ ')';

   int recordsAffected;

   connection.Execute(obfuscatedCommandText, out recordsAffected, adCmdText | adExecuteNoRecords);

   return recordsAffected;
}

更新:更好的解决方法黑客

与其将整个语句包装在 中EXEC(...),我发现击败 ADO 的一个更安全的技巧是在语句之​​前加上注释。即使是空的评论也可以:

--
MERGE Users
USING (VALUES ...

实际上,您需要一些文本来解释空注释行对于使查询正常工作至关重要:

--Leading comment to thwart ADO from mangling MERGE on Windows XP/2003R2
MERGE Users
USING (VALUES ...
4

1 回答 1

2

由于没有解决方案,并且 ADO(虽然不是dead)已经完成,所以 hack就是答案。

切勿在MERGE没有前导注释行的情况下发表声明:

--Dummy leading comment line to thwart ADO from mangling MERGE on Windows XP/2003R2
MERGE Users
USING (VALUES ...
于 2013-07-27T16:34:07.547 回答