Запросы с параметрами

Модераторы: kdv, CyberMax

Ответить
Батор
Сообщения: 21
Зарегистрирован: 11 мар 2007, 23:09

Запросы с параметрами

Сообщение Батор » 30 мар 2007, 04:45

исторически получилось, что вместо параметров в запросах я всегда писал полный текст с помощью Format

т.е. вместо:
Query.SQL.Text:='SELECT * FROM SomeTable WHERE id=:id';
Query.ParamByName('id').Value:=id;
писал:
Query.SQL.Text:=Format('SELECT * FROM SomeTable WHERE id=%d', [id]);

причина такого использования была в том, что параметры при отладке и Query.SQL.SaveToFile('file.sql'); сохраняли не текущие значения, что часто неудобно, да и возникали проблемы с некоторыми типами полей при использовании параметров (сейчас уже не помню какие, но кажется большая часть - с датами).

вопрос: что дает использование параметров, кроме удобства при чтении кода (и то при сильно мнемонических названиях)? и какое ограничение может быть при использовании Format()?

CyberMax
Заслуженный разработчик
Сообщения: 638
Зарегистрирован: 31 янв 2006, 09:05

Сообщение CyberMax » 30 мар 2007, 06:37

Вкратце:
1. Запрос, перед исполнением, сначала надо скомпилировать. Для этого компонента доступа отправляет его текст на сервер (по команде Prepare), и получает от него в скомпилированном виде (BLR), вместе с планом выполнения.
2. Скомпилировав его раз (с параметром), запрос можно выполнять неограниченное число раз, меняя только значения параметров. Использование явных значений требует перекомпилирования при каждом выполнении (если "параметры" не изменились), увеличивая сетевой трафик и время отклика приложения.

SAMZ
Сообщения: 128
Зарегистрирован: 21 мар 2005, 08:17

Re: Запросы с параметрами

Сообщение SAMZ » 30 мар 2007, 06:48

Программирование - это большое, большое поле, на котором каждый при большом желании может топтать свою тропу. Но твоя тропинка, на этом сайте, как мне кажется, будет оценена как проктология.
Не думаю, что на твой вопрос кто - либо будет отвечать детально. Смотри литературу и изучай матчасть.
Насколько можно судить по запросам с датами чаще всего проблемы возникают, когда в запрос вместо параметра DateTime пытаются засунуть строку.

Батор
Сообщения: 21
Зарегистрирован: 11 мар 2007, 23:09

Re: Запросы с параметрами

Сообщение Батор » 30 мар 2007, 07:57

SAMZ писал(а):Программирование - это большое, большое поле, на котором каждый при большом желании может топтать свою тропу. Но твоя тропинка, на этом сайте, как мне кажется, будет оценена как проктология.
мсье ходил такими путями? :)
SAMZ писал(а): Не думаю, что на твой вопрос кто - либо будет отвечать детально. Смотри литературу и изучай матчасть.
собственно, мне кажется специализированный форум для того, чтобы уточнить непонятые моменты и ветка еще более специализированная, соответствует вопросу.
зачем отвечать, если нечего ответить по вопросу?
конечно, можно показать свою крутость знанием фраз "rtfm", "учи матчасть" и т.д.
SAMZ писал(а):Насколько можно судить по запросам с датами чаще всего проблемы возникают, когда в запрос вместо параметра DateTime пытаются засунуть строку.
я не говорил, что проблемы были только с датами.

Батор
Сообщения: 21
Зарегистрирован: 11 мар 2007, 23:09

Сообщение Батор » 30 мар 2007, 08:00

CyberMax писал(а):Вкратце:
1. Запрос, перед исполнением, сначала надо скомпилировать. Для этого компонента доступа отправляет его текст на сервер (по команде Prepare), и получает от него в скомпилированном виде (BLR), вместе с планом выполнения.
2. Скомпилировав его раз (с параметром), запрос можно выполнять неограниченное число раз, меняя только значения параметров. Использование явных значений требует перекомпилирования при каждом выполнении (если "параметры" не изменились), увеличивая сетевой трафик и время отклика приложения.
* как долго хранится скомпилированный результат?
* если у меня очередь из 50 последовательных запросов, то будет ли повторная компиляция?
* если такой же запрос из другого коннекта, компиляция берется старая?

kdv
Forum Admin
Сообщения: 6595
Зарегистрирован: 25 окт 2004, 18:07

Сообщение kdv » 30 мар 2007, 09:37

* как долго хранится скомпилированный результат?
см. дальше.
* если у меня очередь из 50 последовательных запросов, то будет ли повторная компиляция?
какая очередь? Ты о чем?
* если такой же запрос из другого коннекта, компиляция берется старая?
опять ерунда.

все действует только в контексте вызовов Датасета (IBQuery, IBDataSet и т.п.) .Prepare и .Execute.
после Prepare можно выполнить Execute сколько угодно раз.
но кажется большая часть - с датами).
с датами, действительно, самая проктология, когда их в виде строки на сервер кидают, хоть в запросе, хоть через параметр. Передавать надо как DateTime.
По-моему о программерской лени вроде
ParamByName('date').asString:=Edit1.Text
я уже где-то писал.

CyberMax
Заслуженный разработчик
Сообщения: 638
Зарегистрирован: 31 янв 2006, 09:05

Сообщение CyberMax » 30 мар 2007, 09:44

Советую поюзать BT SQL Monitor. Узнаешь много нового :wink:.

WildSery
Заслуженный разработчик
Сообщения: 1738
Зарегистрирован: 05 июн 2006, 16:19

Сообщение WildSery » 30 мар 2007, 10:46

Код: Выделить всё

q.SQL.Text := 'SELECT * FROM TBL WHERE ID = :ID';
q.Prepare; // Тут первая и единственная процедура парсинга и компиляции запроса
while (i < 10000) do begin
  q.ParamByName('ID').AsInteger := i;
  q.ExecQuery;
  // Тут что-то делаем с результатом запроса
  i := i+1;
end;

CyberMax
Заслуженный разработчик
Сообщения: 638
Зарегистрирован: 31 янв 2006, 09:05

Сообщение CyberMax » 30 мар 2007, 11:11

А закрывать набор Пушкин будет? :)

Код: Выделить всё

q.SQL.Text := 'SELECT * FROM TBL WHERE ID = :ID';
q.Prepare; // Тут первая и единственная процедура парсинга и компиляции запроса
while (i < 10000) do begin
  q.ParamByName('ID').AsInteger := i;
  q.ExecQuery;
  // Тут что-то делаем с результатом запроса
  q.Close;
  i := i+1;
end;

Батор
Сообщения: 21
Зарегистрирован: 11 мар 2007, 23:09

Сообщение Батор » 30 мар 2007, 15:31

kdv писал(а):
* если у меня очередь из 50 последовательных запросов, то будет ли повторная компиляция?
какая очередь? Ты о чем?
while i:=... do
begin
Query.SQL:='...';//1
Query.ExecSQL;
...
Query.SQL:='...';//2
Query.ExecSQL;
...
Query.SQL:='...';//49
Query.ExecSQL;
...
Query.SQL:='...';//50
Query.ExecSQL;
...
end;
т.е. в каждой итерации будет использоваться тот же результат по Prepare?
kdv писал(а):
* если такой же запрос из другого коннекта, компиляция берется старая?
опять ерунда.

все действует только в контексте вызовов Датасета (IBQuery, IBDataSet и т.п.) .Prepare и .Execute.
после Prepare можно выполнить Execute сколько угодно раз.
т.е. если я изменю запрос, то Prepare будет заново выполняться?
и параметрический запрос имеет преимущество только, если я один и тот же запрос вызываю несколько раз?
результат Prepare хранится на сервере или в компоненте?
kdv писал(а):
но кажется большая часть - с датами).
с датами, действительно, самая проктология, когда их в виде строки на сервер кидают, хоть в запросе, хоть через параметр. Передавать надо как DateTime.
По-моему о программерской лени вроде
ParamByName('date').asString:=Edit1.Text
я уже где-то писал.
я много лет работал с MySQL, там практически все по-другому, поэтому и задаю вопросы на недопонятые мной моменты :D

CyberMax
Заслуженный разработчик
Сообщения: 638
Зарегистрирован: 31 янв 2006, 09:05

Сообщение CyberMax » 31 мар 2007, 08:05

Батор. Тебе русским языком уже все объяснили. Прочитай, пожалуйста, тему с самого начала. И осмысли написанное.

kdv
Forum Admin
Сообщения: 6595
Зарегистрирован: 25 окт 2004, 18:07

Сообщение kdv » 02 апр 2007, 10:54

т.е. в каждой итерации будет использоваться тот же результат по Prepare?
посмотри код компонент Prepare+Execute это пара методов для ОДНОГО текста запроса.
т.е. если я изменю запрос, то Prepare будет заново выполняться?
разумеется. Prepare "дает возможность" выполнять один и тот же запрос с разным набором параметров.
и параметрический запрос имеет преимущество только, если я один и тот же запрос вызываю несколько раз?
ага
результат Prepare хранится на сервере или в компоненте?
разумеется на сервере. результат prepare это план запроса, структуры, и его код для исполнения сервером.
я много лет работал с MySQL, там практически все по-другому,
да уж прямо по другому. параметры везде одинаковы, а особенности форматов дат известны давно, например с самых первых Windows.

Батор
Сообщения: 21
Зарегистрирован: 11 мар 2007, 23:09

Сообщение Батор » 02 апр 2007, 23:57

по данному вопросу вопросов больше нет :)

Батор
Сообщения: 21
Зарегистрирован: 11 мар 2007, 23:09

Сообщение Батор » 03 апр 2007, 01:05

хотя есть
FIBPlus
TpFIBDataSet

запрос что-то вроде:

SELECT MyTable.id, ... FROM MyTable LEFT JOIN ...
WHERE ...
AND MyTable.id NOT IN (:id_used)
ORDER BY MyTable.id;

дальше в коде пишу:
DataSet.ParamByName('id_used').Value := '123, 124, 125';

и на открытии запроса ошибка, потому, что в DataSet.ParamByName('id_used').Value попадает '123. 124. 125'

из-за чего такие подмены и как побороть не знаю :(
даже в IBExpert такая же фигня выходит

CyberMax
Заслуженный разработчик
Сообщения: 638
Зарегистрирован: 31 янв 2006, 09:05

Сообщение CyberMax » 03 апр 2007, 01:39

Один параметр = один скалярный тип. В твоем случае нужно три раза выполнить запрос с параметром id_used = 123, 124, 125. Будь добр, почитай документацию на ibase.ru.

kdv
Forum Admin
Сообщения: 6595
Зарегистрирован: 25 окт 2004, 18:07

Сообщение kdv » 03 апр 2007, 09:21

из-за чего такие подмены и как побороть не знаю
мда. сила мысли... почему сервер должен соображать что ты в параметр передаешь не строку а некое перечисление неопознанного типа данных, да еще разделенного запятыми, а не точкой с запятой например, или пробелом?

на первый раз предупреждение
а) за неоригинальность идеи
б) за нечтение FAQ: http://www.ibase.ru/ibfaq.htm#inparam

Ответить