Общая ошибка выражения таблицы - PullRequest
4 голосов
/ 12 января 2011

Мне нужно использовать ADODB старой школы (не ADO.NET) для выполнения оператора, содержащего выражение общей таблицы. Я использую (должен использовать) поставщика SQLOLEDB. Оператор DML отлично работает при выполнении с клиента Windows 7 / Windows Server 2008, но не с сервера WinXP или Win2K3. Я профилировал подпрограмму и обнаружил, что старые операционные системы отправляют несколько иной оператор 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, которое я могу применить к старым ОС? или какой-то другой обходной путь.

Ответы [ 2 ]

4 голосов
/ 12 января 2011

(К вашему сведению, вам действительно стоит вернуться к некоторым из ваших существующих вопросов, так как большинство из них, кажется, имеют полезные ответы, которые, как представляется, касаются вопроса; ваши комментарии даже предполагают, что это так. Если у них есть ответ, примите его).

Если вам действительно нужно использовать CTE здесь (имеется в виду, что вы делаете что-то рекурсивное, а не просто используете его для удобства вместо линейного выбора или линейного соединения), самый простой и быстрый обходной путь будетвероятно, стоит включить ваш SQL в ваш собственный вызов sp_executesql.Вы закончите вложенными вызовами (это будет выглядеть глупо), но это не должно вызывать никаких реальных проблем.

1 голос
/ 07 марта 2012

Заключение запроса в оператор sp_executesql прекрасно работает, если у вас нет параметров в запросе, в противном случае параметры не анализируются, потому что они находятся в строке в кавычках к тому времени, как они попадают в ADO, и это приводит к в синтаксической ошибке.

Чтобы решить эту проблему, я создал потомка TADOQuery, который переопределяет конструктор следующим образом:

constructor TCPADOQuery.Create(AOwner: TComponent);
begin
  inherited;
  TWideStringList(SQL).OnChange := LocalQueryChanged;
end;

Затем LocalQueryChanged проверяет, начинается ли запрос с общего табличного выражения, и вставляет в начало запроса фиктивное объявление, которое понимает анализатор XP ADO. 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, и параметры.

...