Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Начинающим";
Текущий архив: 2010.10.31;
Скачать: [xml.tar.bz2];

Вниз

Два почти одинаковых запроса выполняются по разному   Найти похожие ветки 

 
И. Павел ©   (2010-08-10 09:13) [0]

Здравствуйте.
Я работаю с Access в Delphi 7 через ADO, JET.
Первоначальный запрос (SELECT с несколькими LEFT JOIN) выполняется нормально и возвращает 3 записи. Если заменить прямую подстановку двух чисел в строку запроса (с помощью “+ IntToStr(…) +”) на параметры, то запрос возвращает пустую выборку (но если использовать любой из этих двух параметров, а второй IntToStr оставить, то запрос опять будет работать правильно).

Вот первоначальный запрос (он выполняется нормально – возвращает 3 записи):

 DMQ.ADODS.Active := false;
 DMQ.ADODS.CommandText :=
   "SELECT j.kvartira, j.schet, j.familia + "" "" + j.imia + "" "" + j.otchestvo AS FIO, s1.summa AS s1_summa, n.summa AS n_summa, sum(o.summa) AS sum_o_summa, s2.summa AS s2_summa " +
   "FROM (((nachisl AS n " +
   "LEFT JOIN jilci AS j ON (j.id = n.IDJilci AND j.IDDoma = " + IntToStr(id) + ")) " +
   "LEFT JOIN saldo AS s1 ON (s1.IDJilci = n.IDJilci AND s1.god = " + IntToStr(god) + " AND s1.mes = " + IntToStr(mes) + ")) " +
   "LEFT JOIN saldo AS s2 ON (s2.IDJilci = n.IDJilci AND s2.god = " + IntToStr(NextGod) + " AND s2.mes = " + IntToStr(NextMes) + ")) " +
   "LEFT join oplati AS o ON (o.IDJilci = n.IDJilci AND o.god = " + IntToStr(god) + " AND o.mes = " + IntToStr(mes) + ") " +
   "WHERE n.god = " + IntToStr(god) + " AND n.mes = " + IntToStr(mes) + " " +
   "GROUP BY n.id, j.kvartira, j.schet, j.familia + "" "" + j.imia + "" "" + j.otchestvo, s1.summa, n.summa, s2.summa;";
 DMQ.ADODS.Parameters.ParseSQL(DMQ.ADODS.CommandText, true);
 DMQ.ADODS.Open;

Вот запрос, который возвращает пустую выборку (этот запрос отличается от первоначального только тем, что два “+IntToStr(…)+” я заменил на параметры – в коде я их выделил жирным шрифтом):

 DMQ.ADODS.Active := false;
 DMQ.ADODS.CommandText :=
   "SELECT j.kvartira, j.schet, j.familia + "" "" + j.imia + "" "" + j.otchestvo AS FIO, s1.summa AS s1_summa, n.summa AS n_summa, sum(o.summa) AS sum_o_summa, s2.summa AS s2_summa " +
   "FROM (((nachisl AS n " +
   "LEFT JOIN jilci AS j ON (j.id = n.IDJilci AND j.IDDoma = :PIDDoma)) " +
   "LEFT JOIN saldo AS s1 ON (s1.IDJilci = n.IDJilci AND s1.god = " + IntToStr(god) + " AND s1.mes = " + IntToStr(mes) + ")) " +
   "LEFT JOIN saldo AS s2 ON (s2.IDJilci = n.IDJilci AND s2.god = " + IntToStr(NextGod) + " AND s2.mes = " + IntToStr(NextMes) + ")) " +
   "LEFT join oplati AS o ON (o.IDJilci = n.IDJilci AND o.god = " + IntToStr(god) + " AND o.mes = " + IntToStr(mes) + ") " +
   "WHERE n.god = :PNGod AND n.mes = " + IntToStr(mes) + " " +
   "GROUP BY n.id, j.kvartira, j.schet, j.familia + "" "" + j.imia + "" "" + j.otchestvo, s1.summa, n.summa, s2.summa;";
 DMQ.ADODS.Parameters.ParseSQL(DMQ.ADODS.CommandText, true);
 with DMQ.ADODS.Parameters.ParamByName("PIDDoma") do
 begin
   DataType := ftInteger;
   Direction := pdInput;
   Value := id;
 end;
 with DMQ.ADODS.Parameters.ParamByName("PNGod") do
 begin
   DataType := ftInteger;
   Direction := pdInput;
   Value := god;
 end;  

Если параметрами заменить не оба, а только один из “+IntToStr(…)+”, то запрос опять начнет работать правильно, возвращая 3 строки.

Подскажите, пожалуйста, в чем здесь  ошибка? Скорее всего, это я что-то сделал не так, но, может быть, это все же Access или ADO?

Заранее спасибо.


 
И. Павел ©   (2010-08-10 09:14) [1]

Здравствуйте.
Я работаю с Access в Delphi 7 через ADO, JET.
Первоначальный запрос (SELECT с несколькими LEFT JOIN) выполняется нормально и возвращает 3 записи. Если заменить прямую подстановку двух чисел в строку запроса (с помощью “+ IntToStr(…) +”) на параметры, то запрос возвращает пустую выборку (но если использовать любой из этих двух параметров, а второй IntToStr оставить, то запрос опять будет работать правильно).

Вот первоначальный запрос (он выполняется нормально – возвращает 3 записи):

 DMQ.ADODS.Active := false;
 DMQ.ADODS.CommandText :=
   "SELECT j.kvartira, j.schet, j.familia + "" "" + j.imia + "" "" + j.otchestvo AS FIO, s1.summa AS s1_summa, n.summa AS n_summa, sum(o.summa) AS sum_o_summa, s2.summa AS s2_summa " +
   "FROM (((nachisl AS n " +
   "LEFT JOIN jilci AS j ON (j.id = n.IDJilci AND j.IDDoma = " + IntToStr(id) + ")) " +
   "LEFT JOIN saldo AS s1 ON (s1.IDJilci = n.IDJilci AND s1.god = " + IntToStr(god) + " AND s1.mes = " + IntToStr(mes) + ")) " +
   "LEFT JOIN saldo AS s2 ON (s2.IDJilci = n.IDJilci AND s2.god = " + IntToStr(NextGod) + " AND s2.mes = " + IntToStr(NextMes) + ")) " +
   "LEFT join oplati AS o ON (o.IDJilci = n.IDJilci AND o.god = " + IntToStr(god) + " AND o.mes = " + IntToStr(mes) + ") " +
   "WHERE n.god = " + IntToStr(god) + " AND n.mes = " + IntToStr(mes) + " " +
   "GROUP BY n.id, j.kvartira, j.schet, j.familia + "" "" + j.imia + "" "" + j.otchestvo, s1.summa, n.summa, s2.summa;";
 DMQ.ADODS.Parameters.ParseSQL(DMQ.ADODS.CommandText, true);
 DMQ.ADODS.Open;


Вот запрос, который возвращает пустую выборку (этот запрос отличается от первоначального только тем, что два “+IntToStr(…)+” я заменил на параметры – в коде я их выделил жирным шрифтом):

 DMQ.ADODS.Active := false;
 DMQ.ADODS.CommandText :=
   "SELECT j.kvartira, j.schet, j.familia + "" "" + j.imia + "" "" + j.otchestvo AS FIO, s1.summa AS s1_summa, n.summa AS n_summa, sum(o.summa) AS sum_o_summa, s2.summa AS s2_summa " +
   "FROM (((nachisl AS n " +
   "LEFT JOIN jilci AS j ON (j.id = n.IDJilci AND j.IDDoma = :PIDDoma)) " +
   "LEFT JOIN saldo AS s1 ON (s1.IDJilci = n.IDJilci AND s1.god = " + IntToStr(god) + " AND s1.mes = " + IntToStr(mes) + ")) " +
   "LEFT JOIN saldo AS s2 ON (s2.IDJilci = n.IDJilci AND s2.god = " + IntToStr(NextGod) + " AND s2.mes = " + IntToStr(NextMes) + ")) " +
   "LEFT join oplati AS o ON (o.IDJilci = n.IDJilci AND o.god = " + IntToStr(god) + " AND o.mes = " + IntToStr(mes) + ") " +
   "WHERE n.god = :PNGod AND n.mes = " + IntToStr(mes) + " " +
   "GROUP BY n.id, j.kvartira, j.schet, j.familia + "" "" + j.imia + "" "" + j.otchestvo, s1.summa, n.summa, s2.summa;";
 DMQ.ADODS.Parameters.ParseSQL(DMQ.ADODS.CommandText, true);
 with DMQ.ADODS.Parameters.ParamByName("PIDDoma") do
 begin
   DataType := ftInteger;
   Direction := pdInput;
   Value := id;
 end;
 with DMQ.ADODS.Parameters.ParamByName("PNGod") do
 begin
   DataType := ftInteger;
   Direction := pdInput;
   Value := god;
 end;  


Если параметрами заменить не оба, а только один из “+IntToStr(…)+”, то запрос опять начнет работать правильно, возвращая 3 строки.

Подскажите, пожалуйста, в чем здесь  ошибка? Скорее всего, это я что-то сделал не так, но, может быть, это все же Access или ADO?

Заранее спасибо.

PS: уважаемые администраторы, удалите, пожалуйста, первый мой пост. Я там забыл отформатировать код.


 
12 ©   (2010-08-10 09:22) [2]

тупое уточнение, а
DMQ.ADODS.Open; есть во второй раз?


 
И. Павел ©   (2010-08-10 09:24) [3]

> а
> DMQ.ADODS.Open; есть во второй раз?

Да, есть. Я просто забыл его указать.


 
sniknik ©   (2010-08-10 09:28) [4]

> DMQ.ADODS.Parameters.ParseSQL(DMQ.ADODS.CommandText, true);
эта строка в обоих случаях лишняя. в первом параметров нет, во втором есть но не отключено (не показано) авто определение. т.е. в одном случае работает вхолостую, в втором (судя по результату) создает дополнительный набор параметров.

> DataType := ftInteger;
> Direction := pdInput;
это тоже лишнее, тип получается из варианта т.е. присвоение Value := id; если id интеджер даст нужный тип. (вот если бы оно было строкой (?), то предварительное указание типа приведет к конвертации при присвоении другого. насколько помню)


 
12 ©   (2010-08-10 09:29) [5]

попробуй пробелы везде добавить

>  "[сюда]FROM (((nachisl AS n " +
>    "[сюда]LEFT JOIN jilci AS j ON (j.id = n.IDJilci AND j.IDDoma

или подсветить окончательный sql в мемо, перетащить в А и выполнить

идея два
Все это
with DMQ.ADODS.Parameters.ParamByName("PNGod") do
begin
  DataType := ftInteger;
  Direction := pdInput;
  Value := god;
end;

переписать просто как  DMQ.ADODS.Parameters.ParamByName("PNGod").Value := god;


 
И. Павел ©   (2010-08-10 09:35) [6]

> [4] sniknik ©   (10.08.10 09:28)

Спасибо. Просто у меня для задания текста запроса и параметров есть специальный модуль с функциями. Поэтому я вынес их код полностью.
Я установил ParamCheck = false и удалил задания типа и направления параметров, но ошибка осталась. Такой запрос тоже возвращает пустую выборку:\\

 DMQ.ADODS.Active := false;
 DMQ.ADODS.CommandText :=
   "SELECT j.kvartira, j.schet, j.familia + "" "" + j.imia + "" "" + j.otchestvo AS FIO, s1.summa AS s1_summa, n.summa AS n_summa, sum(o.summa) AS sum_o_summa, s2.summa AS s2_summa " +
   "FROM (((nachisl AS n " +
   "LEFT JOIN jilci AS j ON (j.id = n.IDJilci AND j.IDDoma = :PIDDoma)) " +
   "LEFT JOIN saldo AS s1 ON (s1.IDJilci = n.IDJilci AND s1.god = " + IntToStr(god) + " AND s1.mes = " + IntToStr(mes) + ")) " +
   "LEFT JOIN saldo AS s2 ON (s2.IDJilci = n.IDJilci AND s2.god = " + IntToStr(NextGod) + " AND s2.mes = " + IntToStr(NextMes) + ")) " +
   "LEFT join oplati AS o ON (o.IDJilci = n.IDJilci AND o.god = " + IntToStr(god) + " AND o.mes = " + IntToStr(mes) + ") " +
   "WHERE n.god = :PNGod AND n.mes = " + IntToStr(mes) + " " +
   "GROUP BY n.id, j.kvartira, j.schet, j.familia + "" "" + j.imia + "" "" + j.otchestvo, s1.summa, n.summa, s2.summa;";
 DMQ.ADODS.Parameters.ParseSQL(DMQ.ADODS.CommandText, true);
 with DMQ.ADODS.Parameters.ParamByName("PIDDoma") do
   Value := id;
 with DMQ.ADODS.Parameters.ParamByName("PNGod") do
   Value := god;
 DMQ.ADODS.Open;


PS: еще пробовал удалить ParseSQL и выставить ParamCheck - но результат тот же.


 
И. Павел ©   (2010-08-10 09:42) [7]

> [5] 12 ©   (10.08.10 09:29)

Поставил пробелы (в том числе и между параметром и скобкой, на всякий случай) и задал только Value для параметра - все равно ошибка осталась.


 
sniknik ©   (2010-08-10 09:46) [8]

> Просто у меня для задания текста запроса и параметров есть специальный модуль с функциями.
не пользуйся модулем для тестов... тест это должно быть ровно то же самое что ты здесь показываешь.

> но результат тот же.
проверь еще раз. где то что то отличается. можно проверить прямо в дизайне, прописать один запрос увидеть свою пару записей, после прямо в нем заменить на параметры у них (в дизайне) поставить те же значения и посмотреть.

ну и из экзотики (было как то. глюк парсера в какой то версии дельфи видать. сам не получал но обсуждалось)
> = :PIDDoma)
вот тут попробуй поставить пробел между параметром и кавычкой.


 
sniknik ©   (2010-08-10 09:48) [9]

> все равно ошибка осталась.
не ошибка, раз запрос выполняется. что то не так задал, раз результат не устраивает.


 
И. Павел ©   (2010-08-10 10:35) [10]

Я попробовал ввести запрос в Access. Он спросил у меня значения обоих параметров и выполнил запрос. Вернул 3 строки, т.е. как и нужно.

Потом я создал новый проект и поместил на него только ADOConnection, ADODataSet, ADODataSource и Table. В ADODataSet.CommandText задал запрос (вместо параметров подставил свои значения: god = 2010, PIDDoma = 1) – запрос тоже выполнился нормально (вернул 3 записи).

Потом я заменил в CommandText числа ‘2010’ и ‘1’ на параметры, а значение и тип параметров указал в Design Time. В инспекторе объектов установил ADODataSet.Active:=true. И получилась пустая выборка...

Если у кого-нибудь из участников форума найдется время, пожалуйста, посмотрите мою тестовую программу. Она содержит два ADODatsSet, все параметры которых задаются в Design Time. Один из них (где запрос задается без параметров) возвращает 3 строки, а второй (где используются 2 параметра)  - возвращает пустую выборку.

Тестовую программку я сохранил здесь:
http://narod.ru/disk/23584869000/Тестовая%20программа%20для%20Access.rar.html


 
12 ©   (2010-08-10 10:37) [11]


> значение и тип параметров указал в Design Time

а если не указывать?


 
И. Павел ©   (2010-08-10 10:39) [12]

> а если не указывать?

Пробовал не указывать тип параметров - оставить ftString - тогда тоже возвращается пустая выборка.
А если не указать значения параметров, то ADO ругается: "Отсутствует значение для одного или нескольких параметров".


 
И. Павел ©   (2010-08-10 10:41) [13]

> > а если не указывать?

А если просто оставить параметры, созданные ADODataSet автоматически нетронутыми (т.е. со значением null), то тоже возвращается пустая выборка, как и в том случае, если задать значения параметров.


 
12 ©   (2010-08-10 10:52) [14]

а если вообще никуда Design Time  не смотреть,
создать динамически,
спросить что-то тупое (чтоб понять, что работает)
потом перезаписать sql с параметрами и спросить?


 
И. Павел ©   (2010-08-10 11:14) [15]

>[14] 12 ©   (10.08.10 10:52)

Несколько запросов так переписывал - нормально работают. Да и сам этот запрос работает, если заменить параметрами все IntToStr, кроме последнего или первого.
Например, такой запрос нормально выполняется как с параметрами, так и без них:

"SELECT d.nazvanie, d.adres, sum(s1.summa) AS sum_s1_summa, sum(n.summa) AS sum_n_summa, sum(o.summa) AS sum_o_summa, sum(s2.summa) AS sum_s2_summa "
"FROM ((((doma AS d " +
"LEFT JOIN jilci AS j ON j.IDDoma = d.id) " +
"LEFT JOIN saldo AS s1 ON (s1.IDJilci = j.id AND s1.god = :PS1God AND :PS1Mes)) " +
"LEFT JOIN saldo AS s2 ON (s2.IDJilci = j.id AND s2.god = :PS2God AND s2.mes = :PS2Mes)) " +
"LEFT join nachisl AS n ON (n.IDJilci = j.id AND n.god = :PNGod AND n.mes = :PNMes)) " +
"LEFT join oplati AS o ON (o.IDJilci = j.id AND o.god = :POGod AND o.mes = :POMes) " +
"GROUP BY d.id, d.nazvanie, d.adres;"


 
sniknik ©   (2010-08-10 11:24) [16]

проблема скорее всего в том, что условие ограничения внесено в условие объединения...

т.е. j.IDDoma = :PIDDoma надо вынести в WHERE, тогда все работает.


 
sniknik ©   (2010-08-10 11:25) [17]

> Например, такой запрос нормально выполняется как с параметрами, так и без них:
и все таки лучше разделять, "ограничители" от "обьеденителей".


 
И. Павел ©   (2010-08-10 11:42) [18]

sniknik ©
Большое Вам спасибо. Вынес в where и все заработало!
Но глобальное "опараметривание" запросов я все же делать не буду. Оказывается, это может привести к неожиданным результатам.

12 ©
Спасибо.


 
sniknik ©   (2010-08-10 12:23) [19]

> Оказывается, это может привести к неожиданным результатам.
сам удивился. вообще считал подобное смешение "типов" влияющим только на понимание/ясность запросов, а получается может приводить и к логическим ошибкам... (хорошо, что не допускаю подобной путаницы... т.к. работаю с аксесс (mssql подобное понимает)


 
И. Павел ©   (2010-08-10 13:49) [20]

> и все таки лучше разделять, "ограничители" от "обьеденителей".

А как тогда можно будет построить запрос, эквивалентный такому:

SELECT *
FROM a
LEFT JOIN b ON b.id = a.id AND b.value = 100

Ведь если написать

SELECT *
FROM a
LEFT JOIN b ON b.id = a.id
WHERE b.value = 100

То этот запрос не вернет ничего, если не найдет строку с b.value = 100, а первый запрос все равно вернет запись.
Если написать:

SELECT *
FROM a
RIGHT JOIN b ON b.id = a.id
WHERE b.value = 100

то тоже может не вернутся ни одна запись, если найдется b.id = a.id, но, например, с b.value = 200, и эта запись отсеяться в предложении WHERE.


 
12 ©   (2010-08-10 14:22) [21]


> SELECT *
> FROM a
> LEFT JOIN b ON b.id = a.id
> WHERE b.value = 100
>
> То этот запрос не вернет ничего, если не найдет строку с
> b.value = 100, а первый запрос все равно вернет запись.

какую!?!


 
sniknik ©   (2010-08-10 14:24) [22]

> А как тогда можно будет построить запрос, эквивалентный такому:

> SELECT *
> FROM a
> LEFT JOIN b ON b.id = a.id AND b.value = 100


SELECT *
FROM a
LEFT JOIN (SELECT * FROM b WHERE ID = 1) b ON b.ID = a.ID


в принципе, такой даже работать должен быстрее (проверить бы на больших таблицах).


 
sniknik ©   (2010-08-10 14:26) [23]

> какую!?!
;) вот поэтому и считаю подобные непонятными/"мутными"


 
И. Павел ©   (2010-08-10 14:38) [24]

> sniknik ©

Спасибо. Буду делать так. Для интереса протестирую - что быстрее.


> какую!?!

Я имел ввиду, что если таблица a имеет записи (пусть и с a.id <> b.id), то первый запрос вернет для каждой строки таблицы "a" по записи, у которой b.id = NULL.


 
12 ©   (2010-08-10 14:42) [25]


> LEFT JOIN b ON b.id = a.id AND b.value = 100

плохая запись, имхо
на месте компилятора/интерпретатора я бы такие только за деньги пропускал :)



Страницы: 1 вся ветка

Форум: "Начинающим";
Текущий архив: 2010.10.31;
Скачать: [xml.tar.bz2];

Наверх





Память: 0.54 MB
Время: 0.004 c
15-1279760970
Abcdef123
2010-07-22 05:09
2010.10.31
Это Дельфи 2007 баг?


15-1279991329
SaveVideo
2010-07-24 21:08
2010.10.31
Не получается сохранить это видео


2-1281337357
George
2010-08-09 11:02
2010.10.31
Файл в строку или как?


2-1281339806
6ruse
2010-08-09 11:43
2010.10.31
Дата на первое число месяца


2-1281011430
Scot Storch
2010-08-05 16:30
2010.10.31
парсинг имени файла





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский