Страницы

Поиск по вопросам

воскресенье, 26 января 2020 г.

Параметрические запросы в Oracle (Prepared Statement)

#oracle #delphi #sql


Доброго времени суток.
Есть задача: синхронизировать данные с Active Directory через LDAP. Т.е. при нажатии
на какую-то кнопку "Синхронизация" в программе, написанной на Delphi, обновлять все
существующие и добавлять новые записи в БД Oracle. 
Как я понимаю, для этого в Oracle есть операция MERGE INTO [...]. Но чтобы не грузить
БД и не заставлять ее парсить 1500 запросов каждый раз, хотелось бы сделать все это
с использованием подготовленных (параметрических) запросов. С этой БД я работал мало,
поэтому сразу возникли вопросы. Запрос у меня получился приблизительно таким (точный
сказать не могу пока, но вроде такой он и есть):
MERGE INTO testtable USING(
SELECT :field1_s field1, :field2_s field2, :field3_s field3, :field4_s field4 FROM dual
) data ON (data.field4 = testtable.field4)
WHEN MATCHED THEN UPDATE SET testtable.field1 = data.field1, testtable.field2 = data.field2,
testtable.field3 = data.field3
WHEN NOT MATCHED THEN INSERT VALUES(NULL, data.field1, NULL, data.field2, data.field3,
NULL, data.field4)

На field4 в таблице testtable стоит уникальный индекс и по этому полю происходит
проверка на существование данной записи в таблице.
В Delphi я использую компоненты ADO (AdoConnection, AdoQuery) для работы как с базой
Oracle, так и с Active Directory. Я закрепляю за данным запросом параметры field1_s,
field2_s и т.д., а затем задаю последовательно значения для параметров через AdoQuery.Parameters.ParamByName('field1_s').Value.
Когда я вызываю процедуру AdoQuery.ExecSQL, Oracle выдает мне свою ошибку, что не все
параметры были заполнены, а конкретно:
ORA-01008 not all variables bound

Уже что только не делал. Все чего добился - это другая ошибка: ORA-01036: illegal
variable name/number, что конечно же не лучше :)
Теперь еще хотелось бы отметить, что такой же параметрический обычный INSERT отрабатывает
нормально и все данные заносятся в таблицу:
INSERT INTO testtable VALUES(NULL, :field1_s, NULL, :field2_s, :field3_s, NULL, :field4_s)

А следовательно напрашивается вывод о том, что все дело в SQL-запросе. Но вот что
с ним - ума не приложу! Может все дело в подзапросе SELECT, который я использую для
MERGE? Например, может виновата строчка ... FROM dual, которую я добавил только из-за
того что оракл ругался на отсутствие ключевого слова FROM? Если да, то как можно переписать
данный запрос, так чтобы Oracle вставил данные не из существующей таблицы, а новые
данные, которые передает моя программа?
Версию Oracle на сервере точно не могу сказать, но вроде - 11. По крайней мере, клиент
я использую версии 11.
Подскажите, куда мне копать? Надеюсь, объяснил все понятно. Заранее спасибо.
UPD:
Версия Oracle на сервере все-таки 9.2. Параметры в делфи биндю вот так:
q_temp.SQL.Clear;
q_temp.Close;
q_temp.SQL.Add('MERGE INTO testtable USING ' +
         '(SELECT :field1_s, :field2_s, :field3_s, :field4_s FROM dual) ' + ....
 );
q_temp.ParamCheck := true;
q_temp.Prepared := true;

for i := 0 to 10 do begin
    q_temp.Parameters.ParamByName('field1_s').Value := ldapQuery.FieldByName('field1').AsString;
      q_temp.Parameters.ParamByName('field2_s').Value := ldapQuery.FieldByName('field2').AsString;
      q_temp.Parameters.ParamByName('field3_s').Value := ldapQuery.FieldByName('field3').AsString;
      q_temp.Parameters.ParamByName('field4_s').Value := outbuf;
       ldapQuery.Next;
end;

Еще пробывал назначать параметрам типы ftString вручную, но это ничего не поменяло.
Сейчас попробывал сделать идентичный непараметрический SQL-запрос - все работает.
UPD2:
Пока, чтобы не передавать весь запрос целиком много раз, сделал хранимую процедуру
и вызываю теперь ее. Но это все равно - не решение проблемы. Хотел посмотреть логи
сервера, чтоб реально увидеть, что к нему приходит, да что-то не получилось. Например,
утилитка Toad ругается на отсутствие таблицы dbms (права у меня рутовские). Еще пробовал
вот эту вещицу, но она что-то не отображает запросы и корректно не работает. Может
кто-нибудь знает какой-нибудь хороший SQL профайлер для Oracle, так чтобы можно было
логи посмотреть не на сервере (туда у меня доступа нет), а на клиенте? Например, для
MSSQL это SQL Server Profiler.    


Ответы

Ответ 1



ParamCheck включается до назначения SQL запроса. Попробуйте.

Комментариев нет:

Отправить комментарий