Справочник функций

Ваш аккаунт

Войти через: 
Забыли пароль?
Регистрация
Информацию о новых материалах можно получать и без регистрации:

Почтовая рассылка

Подписчиков: -1
Последний выпуск: 19.06.2015

TQuery, синтаксис SQL , глюк или фича?

621
08 августа 2004 года
Бешеный кролик
151 / / 23.03.2004
Всем привет!

Такой запрос работает правильно:

MyQuery->SQL->Text="Update buff set idx=idx+1";
MyQuery->ExecSQL();

А вот такой:

MyQuery->SQL->Text="Update buff set idx=idx+:i";
MyQuery->ParamByName("i")->AsFloat=m;
MyQuery->ExecSQL();

помещает в поле idx нули.

Я, конечно, вышел из положения, сформировав строку запроса, не используя ParamByName, но хотелось бы узнать, что это - тонкости синтаксиса(скорее всего) или глюк?

Спасибо.
10
08 августа 2004 года
Freeman
3.2K / / 06.03.2004
Цитата:
Originally posted by Бешеный кролик
MyQuery->SQL->Text="Update buff set idx=idx+:i";
MyQuery->ParamByName("i")->AsFloat=m;
MyQuery->ExecSQL();


Ничего крамольного в синтаксисе не вижу. Должно работать. А что за база используется?

621
08 августа 2004 года
Бешеный кролик
151 / / 23.03.2004
Цитата:
Originally posted by smartsoft

Ничего крамольного в синтаксисе не вижу. Должно работать. А что за база используется?



База пока все та же - Paradox (помня нашу с вами дискуссию планирую перейти на InterBase, но это пока планы).
Мне интересно - неужели m в моем примере передается в базу как параметр, а не заменяется значением до того, как запрос будет передан базе?
Видимо так, потому что если формировать запрос следующим образом:

MyQuery->SQL->Text="Update buff set idx=idx+"+IntToStr(m);

все работает.

10
08 августа 2004 года
Freeman
3.2K / / 06.03.2004
Цитата:
Originally posted by Бешеный кролик
Мне интересно - неужели m в моем примере передается в базу как параметр, а не заменяется значением до того, как запрос будет передан базе?


Все сервера баз данных делают именно так: SQL передается отдельно, переменные (параметры) - отдельно.

Отделение мух от котлет продиктовано, в первую очередь соображениями производительности. Дело в том, что разбор SQL тоже занимает некоторое время, а после того, как план выполнения запроса построен, он может выполняться какое угодно количество раз. На этом и базируется использование параметров как переменных.

Сказанное справедливо и для выражения UPDATE, поскольку оно обычно содержит WHERE, также разбираемое и выполняемое.

Только вот вопрос реализации для конкретной базы данных - это дело самой базы данных. На серверах обычно проблем с этим не возникает - там просто другого способа манипулирования данными нет. А для BDE - не факт, как может быть реализовано. Может быть, реализация для Paradox и не дает возможность использования параметров при обновлении данных.

621
09 августа 2004 года
Бешеный кролик
151 / / 23.03.2004
sorry
621
09 августа 2004 года
Бешеный кролик
151 / / 23.03.2004
Цитата:
Originally posted by Бешеный кролик
Большое спасибо! Очень хорошо объясняете.

Не могли бы вы, если не трудно, в двух словах прояснить еще один маленький вопрос (я не халявщик и честно читаю доки :), просто начинающий пока)?

Есть у меня след. кусок кода:

MyQuery->SQL->Text="Insert into buff select * from tree where tree.idx=:i";
for (i=0;i<SNodes->Count;i++)
{
ttn=(TTreeNode *)SNodes->Items;
if (ttn->getNextSibling()) kk=ttn->getNextSibling()->AbsoluteIndex;
else kk=TreeView1->Items->Count;
for (j=ttn->AbsoluteIndex;j<kk;j++)
{
MyQuery->ParamByName("i")->AsFloat=*(int *)TreeView1->Items->Item[j];
MyQuery->ExecSQL();
cg->Progress=int(++ppp*100.0/ccc);
}
}

Я хотел убыстрить его немного, и прочитав в хелпе Borland'a следующее:

Call Prepare to have the BDE and a remote database server allocate resources for the query and to perform additional optimizations. Calling Prepare before executing a query improves application performance.

C++Builder automatically prepares a query if it is executed without first being prepared. After execution, C++Builder unprepares the query. When a query will be executed a number of times, an application should always explicitly prepare the query to avoid multiple and unnecessary prepares and unprepares.

Preparing a query consumes some database resources, so it is good practice for an application to unprepare a query once it is done using it. The UnPrepare method unprepares a query.

Note: When you change the text of a query at runtime, the query is automatically closed and unprepared.

Вставил после MyQuery->SQL->Text="Insert into buff select * from tree where tree.idx=:i";

строчку MyQuery->Prepare();

Т.к. думал, что на сервере будет построен и оптимизирован мой запрос, а затем будет только меняться параметр и это сэкономит время.

Однако программа начала ругаться - "Invalid Parameter".

Почему? Что неверно? Ведь текст запроса не меняется (по крйней мере я так ваш предыдущий ответ понял)?

7.9K
09 августа 2004 года
avc
13 / / 04.08.2004
Цитата:
Originally posted by Бешеный кролик


Прошу прощения, что вмешиваюсь, но у меня так работает без проблем:
Query2->SQL->Text = "\
Update biolife.db \n\
Set \"biolife.db\".\"length (cm)\" = \"biolife.db\".\"length (cm)\" + :dlt_len \n\
Where \"biolife.db\".\"Species No\" = :pID \n\
";

Query2->Prepare();
Query2->ParamByName("pID")->AsInteger = 90020;
Query2->ParamByName("dlt_len")->AsInteger = 1;
for (int i=0; i < 10; i++) Query2->ExecSQL();

// смотрим результат
if (Query1->Active) Query1->Active = false;
Query1->Active = true;

621
09 августа 2004 года
Бешеный кролик
151 / / 23.03.2004
Рад всем ответам!
Дело в том, что у вас один Prepare и одно присвоение параметров. Из того куска хелпа, что я привел, я заключил, что это бессмысленно, т.к. PREPARE вызывается автоматически при первом запуске Query (с конкретным запросом). У меня Query вызывается неоднократно (если один раз вызвать - то все работает с Prepare) - проэтому- то я и надеялся на оптимизацию. Smartsoft писал, что запрос и параметры отправляются на сервер отдельно, что ведет к оптимизации. И это очень логично. Однако, видимо, присвоение параметров BDE рассматривает как изменение текста запроса. (Может быть я и неправ).
621
09 августа 2004 года
Бешеный кролик
151 / / 23.03.2004
Да, исходный код, конечно же, содержит глюк. Правильный выглядит вот так:

for (i=0;i<SNodes->Count;i++)
{
ttn=(TTreeNode *)SNodes->Items;
if (ttn->getNextSibling()) kk=ttn->getNextSibling()->AbsoluteIndex;
else kk=TreeView1->Items->Count;
for (j=ttn->AbsoluteIndex;j<kk;j++)
{
ttn1=(TTreeNode *)TreeView1->Items->Item[j];
MyQuery->ParamByName("i")->AsFloat=*(int *)ttn1->Data;
MyQuery->ExecSQL();
cg->Progress=int(++ppp*100.0/ccc);
Application->ProcessMessages();
}

Однако, непонятки с Prepare остаются.
7.9K
09 августа 2004 года
avc
13 / / 04.08.2004
[QUOTE]Originally posted by Бешеный кролик

В таком варианте все продолжает работать и простой просмотр в пошаговом режиме показывает, что Prepare выполняется только 1 раз
Query2->Prepare();
//Query2->ParamByName("pID")->AsInteger = 90020;
Query2->ParamByName("dlt_len")->AsInteger = 1;
for (int i=0; i < 10; i++)
{ Query2->ParamByName("pID")->AsInteger = 90020 + 10 * (i & 1);
Query2->ExecSQL();
}

Если закомментировать Prepare то TQuery.PrepareSQL будет вызываться 10 раз
Параметры дествительно передаются отдельно от запроса (в этом можно убедиться запустив, например, SQL монитор). Иногда это ускоряет, а иногда тормозит. Другое дело, что Paradox это не SQL'евский сервер и я очень сомневаюсь, что он что то оптимизирует.
621
09 августа 2004 года
Бешеный кролик
151 / / 23.03.2004
Хм... работает значит. Тогда, видимо глюк где-то у меня в коде. Буду думать... Спасибо.
Реклама на сайте | Обмен ссылками | Ссылки | Экспорт (RSS) | Контакты
Добавить статью | Добавить исходник | Добавить хостинг-провайдера | Добавить сайт в каталог