我必须使用旧学校ADODB(不是ADO.NET)来执行包含公用表表达式的语句。 我正在使用(必须使用)SQLOLEDB提供程序。 从Windows 7 / Windows Server 2008客户端执行而不是从WinXP或Win2K3服务器执行时,DML语句正常工作。 我已经分析了例程,发现旧操作系统发送的SQL语句略有不同。
Win7 + 2008 = exec sp_executesql N'WITH source(Vsl, Cpt, SrcTyp, SrcNum, Opn, JobNum, Qty, Cst, Vry, Reg, Vnt, Sbk) AS ...'
WinXP + Win2K3 = exec sp_executesql N'exec WITH source(Vsl, Cpt, SrcTyp, SrcNum, Opn, JobNum, Qty, Cst, Vry, Reg, Vnt, Sbk) AS ...'
注意额外的'exec'滑入命令文本。
似乎旧操作系统上SQLOLEDB.1的版本错误地处理了WITH语句,并认为它需要一个前置'exec'。
任何人都可以对此有所了解。是否有可以应用于旧操作系统的SQLOLEDB驱动程序更新?或其他一些解决方法。
答案 0 :(得分:4)
(仅供参考,您应该重新审视一些现有问题,因为他们中的大多数似乎都有有用的答案似乎可以解决这个问题;您的意见甚至暗示这是如此。如果他们有答案,请接受)
如果你真的需要在这里使用CTE(这意味着你正在做一些递归的事情并且不仅仅是为了方便使用它而不是内联选择或内联加入),最简单和最快速的解决方法可能包括您在自己的sp_executesql
调用中的SQL。你最终会嵌入对它的调用(看起来很傻),但它不应该导致任何实际问题。
答案 1 :(得分:1)
如果在查询中没有参数,则在sp_executesql语句中包装查询会很有效,否则参数不会被解析,因为它们在到达ADO时都是带引号的字符串,这会导致结果在语法错误。
我解决这个问题的方法是创建一个TADOQuery后代,它会覆盖构造函数,如下所示:
constructor TCPADOQuery.Create(AOwner: TComponent);
begin
inherited;
TWideStringList(SQL).OnChange := LocalQueryChanged;
end;
LocalQueryChanged然后检查查询是否以公用表表达式开头,并在查询开头插入一个虚拟声明,XP ADO解析器确实理解。如果CTE不是查询中的第一个语句,则CTE必须以分号开头,因此我们必须先修复它:
procedure TCPADOQuery.LocalQueryChanged(Sender: TObject);
var
a: WideString;
begin
if not (csLoading in ComponentState) then
Close;
a := Trim(SQL.Text);
if Uppercase(copy(a, 1, 4)) = 'WITH' then a := ';' + a;
if Uppercase(copy(a, 1, 5)) = ';WITH' then
a := 'DECLARE @DummyForADO_XP BIT'#13#10 + a;
CommandText := a;
end;
这解决了这个问题,并且让我不得不重新编写我使用CTE和参数的所有代码。