Top.Mail.Ru
Мастера DELPHI, Delphi programming community Титульная страница Поиск, карта сайта Написать письмо 
| Новости | Поиск | FAQ | Статьи | Книги | Новости VCL |
| Форумы ЧАТ | Орешник | KOL и MCK |
Форумы -» Основная («Начинающим»)/ Базы / WinAPI / Компоненты / Сети / Media / Игры / Corba и COM / KOL / FreePascal / .Net / Прочее / RSDN.ORG

« предыдущая ветвь | форум | следующая ветвь »

[D2010] Магия мыши в TSQLQuery + DateTimePicker [MySQL]


Страницы:   1 2 3 4 5

megavoid ©   (2010-12-14 20:13:00) 

Здравствуйте, Мастера!

Столкнулся с такой проблемой:
Есть форма, на ней stringgrid, sqlquery, datetimepicker. Юзеры выбирают дату в datetimepicker, в onChange конструируется select с нужной датой, выполняется через query, в цикле (query.next) читаю ответ от query и заполняю stringgrid нужными значениями. Всё вроде бы шоколадно, но есть одно но - если выбирать значение в picker'e мышью (sic!), то query при попытке интерпретировать ответ (.asString, .asInteger) выдаёт ошибку: Query: Field 'N1' not found. Не всегда выдаёт, произвольно, один раз из десяти-пятнадцати. Если же выбирать дату в пикере стрелочками, всё прекрасно, никакой ошибки. Более того, по событию FormCreate отрабатывает datetimepickerchange(self), и при запуске проги в гриде тоже всё прекрасно отображено.

Усугубляет разброд в моём мозге то, что поидее сообщения вообще выдаваться не должно бы (try..except), а оно выдаётся :)

Выглядит же этот безобразный цикл примерно так:

try
 Query.Open;
 for j := 0 to query.RecordCount-1 do begin
   // здесь идут блоки s := fieldbyname .asstring; .asinteger; итд
   try
     S := query.FieldByName('N1').AsString;
   except
   end;
   // здесь мы эти s пихаем в stringgrid
   Query.Next;
   Application.ProcessMessages;
 end;
finally
 Query.Close;
end;


При возникновении этого глюка отладчик вылетает в окно CPU, а не на строку между try..except. Стэк вызовов процедур получается такой:
KERNELBASE.RaiseException
DatabaseError
DatabaseErrorFmt
Dataset.FieldByName
стоп указывает на инструкцию leave
перед ней call dword ptr [$7555116c] - что там у меня по этому адресу - Готт его знает, перешёл туда - там jnbe, перед ней ещё пара инструкций и нули, много-много нулей :) Увы, мой ассемблер закончился в досе на уровне mov ah, 9 int 21h, так что мне это ровным счётом ничем не помогло :)

Вопрос: что же всё-таки её вызывает, ошибку эту, если мышкой выбирать дату? Пока вопрос решён чисто по-русски, то есть юзеры (~80 человек) не выбирают мышкой, но мучит меня совесть и интерес профессиональный, что ж за фигня такая :)
Плиз хелп, всем заранее спасибо!


megavoid   (2010-12-15 12:13:00) [61]

ну, хоть на расстрел набежали, и то радует
повторюсь, проблема не в том, что что-то не работает, а в том, что всё работает.

@sniknik [20]
сделал сразу же, результат в [8]

> указывать * в запросе есть плохой тон. sql движок это напрягает.
что же мне указывать, если мне все поля нужны? перечислять их все через запятую?

вот тот самый метод полностью

procedure TForm1.FillGrid(Grid: TZColorStringGrid; Req: String);
var
 i, j, QCash, zal, rating: integer;
 S, Trainer, Clients, Task, RatingStr: string;
begin
 InitGridLines;
 Qry.Close;
 Qry.SQL.Clear;
 Qry.SQL.Add(Req + ';');
 // showmessage(Qry.sql.text);  // !!
 // for j := 0 to qry.Params.Count-1 do showmessage(qry.params[i].Name + qry.params[i].value);  // !!
 try
   Qry.Open;
   // if Qry.IsEmpty then showmessage('Пусто'); // !!
   for j := 0 to Qry.RecordCount-1 do begin
     // for i := 0 to 9 do showmessage(qry.fields[i].FieldName + qry.fields[i].asstring);    // !!
     try
       S := TimeToStr(Qry.FieldByName('dtime').AsDateTime);
     except
       on E: Exception do
         ShowMessage(E.Message + #13#10 + qry.SQL.Text);
     end;
     try
       i := StrToInt(Copy(S,0,Pos(':',S)-1)) - 6;
     except
     end;
     QCash := Qry.FieldByName('cash').AsInteger;
     Zal := Qry.FieldByName('zal').AsInteger;
     Rating := Qry.FieldByName('rating').AsInteger;
     Trainer := FIO2ShortFIO( Qry.FieldByName('trainer').AsString );
     Clients := Qry.FieldByName('client').AsString;
     Task := Qry.FieldByName('task').AsString;

     if Rating = 0 then RatingStr := ''
       else RatingStr := ' (' + IntToStr(Rating) + '*)';
     // one or more tasks at one time
     if Grid.Cells[i, Zal] = '' then begin
       if QCash = 3 then
         Grid.Cells[i, Zal] :=  Trainer + '[' + Task + ']' + RatingStr
       else
         Grid.Cells[i, Zal] :=  Trainer + '[' + Task + ']' + #13#10 + Clients;
     end else begin
       if QCash = 3 then
         Grid.Cells[i, Zal] :=
           Grid.Cells[i, Zal] + #13#10#13#10 + Trainer + '[' + Task + ']' + RatingStr
       else
         Grid.Cells[i, Zal] :=
           Grid.Cells[i, Zal] + #13#10#13#10 + Trainer + '[' + Task + ']' + #13#10 + Clients;
         //Grid.CellStyle[i, Zal].WordWrap := True;
     end;
     if QCash = 3 then
       Grid.CellStyle[i, Zal].BGColor := clSetka   // сетка
     else {if Zal = 1 then}
       Grid.CellStyle[i, Zal].BGColor := clZal;    // 1 зал
     Qry.Next;
     Application.ProcessMessages;
   end;
 except
   on E: Exception do
     ShowMessage(E.Message + #13#10 + Qry.SQL.Text);
   // Qry.Close;   // finally
 end;
 Qry.Close;
 AutoSizeGrid(Grid);
end;


вызывается он так:

procedure TForm1.DateTimePicker1Change(Sender: TObject);
begin
 FillGrid(StringGrid1, 'SELECT * FROM z WHERE ddate = ' + fd2sql(datetimepicker1.DateTime));
end;


fd2sql (c) Белов Владимир

function TForm1.FD2SQL(ADateEdit : TDateTime) : string;
var Year, Month, Day : word;
s : string;
begin
 if ADateEdit = 0 then Result:='NULL'
else begin
 DecodeDate(ADateEdit, Year, Month, Day);
 s:='';
 s:=s+IntToStr(Year)+'-';
 if Month < 10 then s:=s+'0';
 s:=s+IntToStr(Month)+'-';
 if Day < 10 then s:=s+'0';
 s:=s+IntToStr(Day);
 // s:=s+' 00:00:00';
 Result:=chr($27)+s+chr($27);
end;
end;


вот, так есть. всё работает.
ошибка возникает, если выбрать дату в tdatetimepicker мышкой.


sniknik   (2010-12-15 12:12:00) [62]

> но и Trunc - тоже бывает глючит. Я заводил тему, как-то.
Trunc вряд ли, а вот это -

> Q.Params[i]. Value:=
возможно. из-за того, что при не заданности типа ADO к примеру берет его из присваиваемого "варианта", а присваиваемый "вариант" получается из приведенного значения, т.е. integer-а в случае с Trunc

> но, если
> TDateTime(Trunc( datetimepicker.date))
> то ошибку ODAC пишет, дескать я хочу время, а мне суют число
видимо с точки зрения оптимизатора подобное приведение типа не существенно (все одно числа туда сюда автоматом приводятся)

> но, на деле вот так вот работает, а иначе - нет.
иначе можно еще тип параметру явно указать, перед значением, и значит "автоопределением" из варианта.


Anatoly Podgoretsky   (2010-12-15 11:26:00) [63]

> 12  (15.12.2010 10:45:28)  [28]

Это Trunc - тоже бывает глючит, там же нет места для глюка, это выполняет
процессор, он просто обрезает дробную часть. Если бы был глюк по этой части
уже стоял гигантский крик в Интернет.


12   (2010-12-15 10:45:00) [64]


> sniknik ©   (15.12.10 09:53) [24]
>
> 12 ©   (15.12.10 08:44) [21]
> > Query.parambyname('DATE').asDAtetime / или ).value / :
> =  datetimepicker.date;
> дата в датапикере тоже типа дататайм, т.что могут быть проблемы,
>  если где оставить "огрызки времени", причем неожиданно,
>  и непонятно (например в XP работает, в win 7 почему то
> нет. сталкивался с подобным).
> лучше, для гарантии, делать например так
> asDateTime:= Trunc(datetimepicker.date);

Согласен.
эт я для простоты
но и Trunc - тоже бывает глючит. Я заводил тему, как-то.
 try
   Q.SQL.Text := SQL;
   s := '';
   for i := 0 to Q.ParamCount-1 do
   begin
     case Q.Params[i].DataType of
       ftDateTime: Q.Params[i].AsDateTime := P[i];
       else Q.Params[i].Value := P[i];
     end;
     s := s + Q.Params[i].Name + '=' + Q.Params[i].AsString + #13#10;
   end;
   Q.Open;

теперь пишу так:
TDateTime(StartOfTheDay( datetimepicker.date))

хотя не понятно, ведь
function StartOfTheDay(const AValue: TDateTime): TDateTime;
begin
 Result := Trunc(AValue);
end;

но, если
TDateTime(Trunc( datetimepicker.date))

то ошибку ODAC пишет, дескать я хочу время, а мне суют число

с другой стороны, число и есть время.

но, на деле вот так вот работает, а иначе - нет.


Anatoly Podgoretsky   (2010-12-15 10:09:00) [65]

> Ega23  (15.12.2010 10:06:26)  [26]

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


Ega23   (2010-12-15 10:06:00) [66]


> Не, его просто развели как лоха на покупку Дельфи.


Ха. Ха. Ха.
Купил.


Anatoly Podgoretsky   (2010-12-15 10:03:00) [67]

> sniknik  (15.12.2010 09:53:24)  [24]

Не, его просто развели как лоха на покупку Дельфи.


sniknik   (2010-12-15 09:53:00) [68]

12 ©   (15.12.10 08:44) [21]
> Query.parambyname('DATE').asDAte time/ или ).value / :=  datetimepicker.date;
дата в датапикере тоже типа дататайм, т.что могут быть проблемы, если где оставить "огрызки времени", причем неожиданно, и непонятно (например в XP работает, в win 7 почему то нет. сталкивался с подобным).
лучше, для гарантии, делать например так
asDateTime:= Trunc(datetimepicker.date);

> Не это ты лох.
в этом нет сомнений, как только начинаются "доказательства" типа "у меня все правильно", только почему то не работает... и "что вы придираетесь к показанному коду" (а к чему еще?) "проблема не в нем, а в том про что я для вас фантазирую" вместо твердых "вот что есть, вот как делается, при этом при вот таких условиях, вот такая ошибка".


Плохиш   (2010-12-15 09:50:00) [69]


> megavoid   (15.12.10 00:26) [16]
> > Не факт. Впрочем, это твоё дело.
> ну тогда мне остаётся лишь признать, что создатели дельфи
> - полнейшие лохи

Ламер-дерьмокодер детектед.


Anatoly Podgoretsky   (2010-12-15 09:10:00) [70]


> ну тогда мне остаётся лишь признать, что создатели дельфи
> - полнейшие лохи, ведь они и сами об этом не знают!

Не это ты лох.

И все то у тебя есть, вот только мы об этом узнаем потом.


12   (2010-12-15 08:44:00) [71]


> for j := 0 to qry.Params.Count-1 do showmessage(qry.params[i].
> Name + qry.params[i].value);
> гм, ничего не показывается

а для чего было написано? :)


> 'SELECT * from table WHERE date=' + format2sql(datetimepicker.
> date) + ';');

Query.sql.text := 'SELECT * from table WHERE date= :DATE';
Query.parambyname('DATE').asDAtetime / или ).value / :=  datetimepicker.date;
Query.open;


sniknik   (2010-12-15 08:02:00) [72]

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

Ega23 ©   (14.12.10 22:24) [6]
Ещё раз, возьми и сделай следующее:
  try
    S := query.FieldByName('N1').AsString;
  except on E: Exception do
      ShowMessage(E.Message + #13#10 + query.SQL.Text);
  end;

И после этого станет ясно, где там и чего not found.

+
> Query.Add('SELECT * from table WHERE date=' + format2sql(datetimepicker.date) + ';');
1 указывать * в запросе есть плохой тон. sql движок это напрягает.
2 параметры.

> приведите мне, пожалуйста, пример, когда TSqlQuery в этом случае вернёт мне НЕ ВСЕ нужные записи.
а что ты знаешь о серверных курсорах? запрос тут совершенно ни при чем. достаточно самого факта его использования. оно просто так работает. асинхронно.


megavoid   (2010-12-15 04:50:00) [73]

В этом проекте 20 форм и более 100 запросов. SQLQuery один. Все они (запросы) for i < recordcount всегда отрабатывают нормально (open/execsql). Кроме этого случая с выбором даты в пикере мышью.


megavoid   (2010-12-15 04:37:00) [74]

@sniknik

> > впрочем, делу это не помогает нисколечко :(а чем это должно
> помочь? могло бы, если бы прислушивался к советам, а так.
> . нет.

Единственный совет, к которому я не прислушался - это переделать цикл с предусловия for на постусловие while. Всё остальное из ответов я проделал с прилежностью ученика церковно-приходской школы, и привёл все полученные результаты в топике.

Query.Clear;
Query.Add('SELECT * from table WHERE date=' + format2sql(datetimepicker.date) + ';');
Query.Open;
try
 /* приведите мне, пожалуйста, пример, когда TSqlQuery в этом случае вернёт мне НЕ ВСЕ нужные записи. Может быть, я с этим просто не столкнулся. Обычно возвращается в среднем порядка 100 записей. */
 for i := 0 to Query.RecordCount-1 do begin
     // here are we're getting info from answer
   Query.Next;
 end;
finally
 Query.Close;
end;

Во всех примерах использования dbExpress без отображения в dbgrid, для простого формирования запроса к БД указан именно этот путь - делаем запрос, open, читаем записи next, закрываем sqlquery. Если база не возвращает результат - используем execsql. Можно, конечно, и переделать цикл на while not eof, если recordcount врёт, но с чего ему врать? В той же документации указано, что RecordCount содержит количество записей в наборе данных однонаправленного датасета.


sniknik   (2010-12-15 02:09:00) [75]

> впрочем, делу это не помогает нисколечко :(
а чем это должно помочь? могло бы, если бы прислушивался к советам, а так.. нет.

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

> ау, эксперты, откликнитесь пожалуйста!!!
тебе уже сказали, или следуй советам, и переделывай, даже не понимая причин, или... "это твоё дело", как бы переубеждать "насильно" это тебе нужны другие эксперты.


megavoid   (2010-12-15 00:26:00) [76]

> Не факт. Впрочем, это твоё дело.
ну тогда мне остаётся лишь признать, что создатели дельфи - полнейшие лохи, ведь они и сами об этом не знают!

http://docs.embarcadero.com/products/rad_studio/delphiAndcpp2009/HelpUpdate2/EN/html/delphivclwin32/SqlExpr_TSQLQuery.html

http://docs.embarcadero.com/products/rad_studio/delphiAndcpp2009/HelpUpdate2/EN/html/devwin32/5datasetusingunidirectionalresultsets_xml.html

впрочем, делу это не помогает нисколечко :(
ау, эксперты, откликнитесь пожалуйста!!!


Ega23   (2010-12-14 23:59:00) [77]


> Поэтому все данные будут у меня сразу после TSQLQuery.Open


Не факт. Впрочем, это твоё дело.


megavoid   (2010-12-14 23:24:00) [78]

@Ega23
Хочется выть и биться об стол головой :)
Где вы у меня TDBGrid и DataSet увидели??? у меня TStringGrid и TSQLQuery!!!
Поэтому все данные будут у меня сразу после TSQLQuery.Open, а потом вручную данные из Query я вношу в StringGrid с нужным заказчику форматированием.


Ega23   (2010-12-14 23:14:00) [79]


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


Во, кстати. если ты внимательно просмотришь код TDBGrid, то ты увидишь, что он берёт строго те данные, которые в данный момент отображаются на экране.
Это возвращаясь к моему предыдущему посту.
Представь, что выборка у тебя на 100 записей. На экране в данный момент ты видишь первые 20. Остальные могут уже находиться в DataSet, могут ещё продолжать "подсасываться". А могут подсосаться тогда, когда ты грид проскроллишь.


Ega23   (2010-12-14 23:10:00) [80]


> Поэтому я не вижу здесь принципиальной разницы между for
> и while


Ещё раз: это тебе дружеский совет. Следовать ему или нет - это твоё дело.
Но RecordCount будет точно определён, когда данные полностью зафетчатся. До конца. А гарантии, что это произойдёт строго после DataSet.Open - нет. Это зависит от настроек конкретной реализации DataSet и от драйвера доступа.


Страницы:   1 2 3 4 5

Наверх

Титульная страница Поиск, карта сайта Написать письмо