-
Здравствуйте, Мастера! Столкнулся с такой проблемой: Есть форма, на ней 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
try
S := query.FieldByName('N1').AsString;
except
end;
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 человек) не выбирают мышкой, но мучит меня совесть и интерес профессиональный, что ж за фигня такая :) Плиз хелп, всем заранее спасибо!
-
чего показывает
> try showmessage(Query.sql.text); > Query.Open; > for j := 0 to query.ParamCount-1 do showmessage(query.params[i].Name + query.params[i].value);
if Query.IsEmpty then showmessage('Пусто'); > for j := 0 to query.RecordCount-1 do begin showmessage(query.fields[i].FieldName + query.fields[i].asstring); > // здесь идут блоки s := fieldbyname .asstring; .asinteger; > итд > try > S := query.FieldByName('N1').AsString; > except > end; > // здесь мы эти s пихаем в stringgrid > Query.Next; > Application.ProcessMessages; > end; > finally > Query.Close; > end;
-
> > try > > S := query.FieldByName('N1').AsString; > > except > > end;
а за это тут расстреливают :)
-
showmessage(Query.sql.text) как и положено, показывает нужный SELECT for j := 0 to query.ParamCount-1 do showmessage(query.params[i].Name + query.params[i].value); только всё-таки так: for j := 0 to qry.Params.Count-1 do showmessage(qry.params[i].Name + qry.params[i].value); гм, ничего не показывается showmessage(query.fields[i].FieldName + query.fields[i].asstring); тоже немножечко не то :) у меня получилось: for i := 0 to 9 do showmessage(qry.fields[i].FieldName + ':' + qry.fields[i].asstring); выводит что и положено, имя поля бд со значением из ответа try .. except end; я прикрутил специально из-за этой вот ситуации, уж не по уши деревянный же, понимаю, что расстреливают )) если есть ошибка, её надо обработать :) повторюсь, алгоритм нормальный, работает нормально. даже когда вылазит эта ошибка, все данные отображены. если ответ empty, то тоже всё нормально! беда в том, что если выбирать дату мышкой (или слишком быстро клавой), то вылазит вот этот вот мерзкий query: field not found, хотя все fields на самом деле есть и всё отображается нормально.
-
> showmessage(Query.sql.text) как и положено, показывает нужный > SELECT
1. А ты его в тот самый except поставь. Пустое гашение исключения надо ещё хорошенько обосновать. У меня на практике такое всего пару раз было. 2. Никогда не любил DateTimePicker, всегда Rx-овским пользовался. 3. На OnChange закладываться точно не стал бы. Представь, что ты хочешь на пару месяцев вперёд пролистать, а у тебя на каждом месяце выборка пойдёт. Нехорошо. Положи кнопочку "Обновить", пусть пользователь спокойно выберет дату, а потом уже получает данные.
-
@Extended Graphics Array 1. Хоспади, да что вы к этому исключению привязались, не глядите на него, нету его там, нету, я пытаюсь лишь подавить сообщение об ошибке, это удовлетворило бы меня на 101% в этом случае. Нету там такого, там s1 = query.FieldByName('N1').AsString;
s2 = query.FieldByName('N2').AsString;
s3 = query.FieldByName('N3').AsString;
Всё и так внутри try..finally, без всяких try..except, это никоим образом не влияет ни на что там. Этот except я ввёл, разбираясь в этой ситуации, пытаясь подавить злосообщение. 2. Нельзя использовать сторонние компоненты, не входящие в стандартную поставку дельфи. Даже бесплатные. Даже JEDI. Это придумал не я. 3. Не поверите. Рядом с пикером лежит кнопка обновить. По ней (хе-хе) вызывается OnChange(Self) пикера. Я представлял - юзеры в 99.9% случаев листают на день-два вперёд назад, обычно даже не листают вообще (в грид выводится график на сегодня, им больше и не надо, изредка на завтра). Да, выборка идёт. Занимает 2-3 секунды. Юзеры не расстраиваются. Гораздо больше они расстраиваются из-за field not found :'(
-
> Хоспади, да что вы к этому исключению привязались, не глядите > на него, нету его там, нету,
Как это нету, когда "Field not found"? А исключение - это для тебя. Между прочим - бесценная информация. Чтобы было понятно, где что происходит. Ещё раз, возьми и сделай следующее: try
S := query.FieldByName('N1').AsString;
except on E: Exception do
ShowMessage(E.Message + #13#10 + query.SQL.Text);
end; И после этого станет ясно, где там и чего not found.
-
> По ней (хе-хе) вызывается OnChange(Self) пикера.
Это неправильно. Хотя бы потому, что Self (с вероятностью 99%) - это объект класса твоей формы. И с какого перепуга ты его в качестве Sender передаёшь пикеру - непонятно. Это не значит, что так делать запрещено, но ты делаешь неправильно (скорее всего потому, что не разобрался, для чего Sender используется). Возьми заведи себе метод TForm1 = class (TForm) private ..... procedure UpdateDBData;
И дёргай его, что по нажатию на кнопку, что в OnChange пикера.
-
да ё же моё!!! try
S := TimeToStr(Qry.FieldByName('dtime').AsDateTime);
except
on E: Exception do
ShowMessage(E.Message + #13#10 + qry.SQL.Text);
end;
получаем:
Qry: Field 'dtime' not found
и мой SELECT
[OK]
а потом Qry: Cannot perform this operation on a closed dataset. я же не просто так тут распинаюсь :) Self - объект класса формы, верно. С таким же успехом можно передавать пикеру nil или что угодно, всё равно sender у меня внутри onchange пикера не используется. Метод такой у меня уже есть. Гридов много, пикеров много. В метод я передаю нужный грид и нужный пикер. Дело не в этом.
-
> Cannot perform this operation on a closed dataset.
И чего непонятного? У тебя набор данных закрыт. Почему - это другой вопрос.
-
Да, и ещё один момент. Вот это: try
Query.Open;
for j := 0 to query.RecordCount-1 do begin перепиши и больше так не делай. 1. Открытие вынеси за try 2. Если не хочешь граблей получить, то обходи набор данных через while. Совершенно необязательно, что ты данные получил до конца, это зависит от драйвера доступа и настроек сервера. Шаблон примерно такой: with Query do
begin
Open;
try
First;
while not Eof do
begin
try
..... Работаем с данными
finally
Next;
end;
end;
finally
Close;
end;
end;
-
@Ega23
>> И чего непонятного? У тебя набор данных закрыт. >> Почему - это другой вопрос. мне непонятно, почему грид правильно берёт все данные из якобы "закрытого набора". Повторяю, всё работает нормально!!! Если выбирать дату в пикере мышкой - то всё тоже работает нормально!!! Но изредка!!! вылазит сообщение об ошибке!
1. Оно так и есть. Набирал тут, поэтому и всобачил Open после try. Извиняюсь.
2. Софт уже три месяца в эксплуатации. Все данные всегда получаются нормально, до конца (см. пп. всё работает!!!). Поэтому я не вижу здесь принципиальной разницы между for и while - я ж не убиваю эти данные в qry, они никуда не денутся, что в for 0..count-1, что в while, а памяти на переменную i мне не жалко, да и небось компилятор соптимизирует сам до while, уберёт её.
-
> Поэтому я не вижу здесь принципиальной разницы между for > и while
Ещё раз: это тебе дружеский совет. Следовать ему или нет - это твоё дело. Но RecordCount будет точно определён, когда данные полностью зафетчатся. До конца. А гарантии, что это произойдёт строго после DataSet.Open - нет. Это зависит от настроек конкретной реализации DataSet и от драйвера доступа.
-
> мне непонятно, почему грид правильно берёт все данные из > якобы "закрытого набора".
Во, кстати. если ты внимательно просмотришь код TDBGrid, то ты увидишь, что он берёт строго те данные, которые в данный момент отображаются на экране. Это возвращаясь к моему предыдущему посту. Представь, что выборка у тебя на 100 записей. На экране в данный момент ты видишь первые 20. Остальные могут уже находиться в DataSet, могут ещё продолжать "подсасываться". А могут подсосаться тогда, когда ты грид проскроллишь.
-
@Ega23 Хочется выть и биться об стол головой :) Где вы у меня TDBGrid и DataSet увидели??? у меня TStringGrid и TSQLQuery!!! Поэтому все данные будут у меня сразу после TSQLQuery.Open, а потом вручную данные из Query я вношу в StringGrid с нужным заказчику форматированием.
-
> Поэтому все данные будут у меня сразу после TSQLQuery.Open
Не факт. Впрочем, это твоё дело.
-
-
> впрочем, делу это не помогает нисколечко :( а чем это должно помочь? могло бы, если бы прислушивался к советам, а так.. нет.
по второй ссылке про однонаправленные датасеты, косвенное подтверждение словам Ega23 про неопределенность RecordCount и все проблемы с этим связанные. т.к. однонаправленные могут быть только с серверным курсором, а для серверных это актуально... и то, что "через раз" тоже, т.к. успевает - работает, а чуть "повезло" быстрее сработать - глюк.
> ау, эксперты, откликнитесь пожалуйста!!! тебе уже сказали, или следуй советам, и переделывай, даже не понимая причин, или... "это твоё дело", как бы переубеждать "насильно" это тебе нужны другие эксперты.
-
@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 содержит количество записей в наборе данных однонаправленного датасета.
-
В этом проекте 20 форм и более 100 запросов. SQLQuery один. Все они (запросы) for i < recordcount всегда отрабатывают нормально (open/execsql). Кроме этого случая с выбором даты в пикере мышью.
-
> Единственный совет, к которому я не прислушался как бы тыкать носом в проигнорированное тут тоже никому не нужно, но один раз по такой настойчивой просьбе...
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 в этом случае вернёт мне НЕ ВСЕ нужные записи. а что ты знаешь о серверных курсорах? запрос тут совершенно ни при чем. достаточно самого факта его использования. оно просто так работает. асинхронно.
-
> 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;
-
> ну тогда мне остаётся лишь признать, что создатели дельфи > - полнейшие лохи, ведь они и сами об этом не знают!
Не это ты лох.
И все то у тебя есть, вот только мы об этом узнаем потом.
-
> megavoid (15.12.10 00:26) [16] > > Не факт. Впрочем, это твоё дело. > ну тогда мне остаётся лишь признать, что создатели дельфи > - полнейшие лохи
Ламер-дерьмокодер детектед.
-
12 © (15.12.10 08:44) [21] > Query.parambyname('DATE').asDAtetime / или ).value / := datetimepicker.date; дата в датапикере тоже типа дататайм, т.что могут быть проблемы, если где оставить "огрызки времени", причем неожиданно, и непонятно (например в XP работает, в win 7 почему то нет. сталкивался с подобным). лучше, для гарантии, делать например так asDateTime:= Trunc(datetimepicker.date);
> Не это ты лох. в этом нет сомнений, как только начинаются "доказательства" типа "у меня все правильно", только почему то не работает... и "что вы придираетесь к показанному коду" (а к чему еще?) "проблема не в нем, а в том про что я для вас фантазирую" вместо твердых "вот что есть, вот как делается, при этом при вот таких условиях, вот такая ошибка".
-
> sniknik (15.12.2010 09:53:24) [24]
Не, его просто развели как лоха на покупку Дельфи.
-
> Не, его просто развели как лоха на покупку Дельфи.
Ха. Ха. Ха. Купил.
-
> Ega23 (15.12.2010 10:06:26) [26]
Купил, или ты думаешь, что это он возмущается по поводу ворованой, взломаной? Тогда это вообще двойной лох.
-
> 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 пишет, дескать я хочу время, а мне суют число с другой стороны, число и есть время. но, на деле вот так вот работает, а иначе - нет.
-
> 12 (15.12.2010 10:45:28) [28]
Это Trunc - тоже бывает глючит, там же нет места для глюка, это выполняет процессор, он просто обрезает дробную часть. Если бы был глюк по этой части уже стоял гигантский крик в Интернет.
-
> но и Trunc - тоже бывает глючит. Я заводил тему, как-то. Trunc вряд ли, а вот это -
> Q.Params[i].Value:= возможно. из-за того, что при не заданности типа ADO к примеру берет его из присваиваемого "варианта", а присваиваемый "вариант" получается из приведенного значения, т.е. integer-а в случае с Trunc
> но, если > TDateTime(Trunc( datetimepicker.date)) > то ошибку ODAC пишет, дескать я хочу время, а мне суют число видимо с точки зрения оптимизатора подобное приведение типа не существенно (все одно числа туда сюда автоматом приводятся)
> но, на деле вот так вот работает, а иначе - нет. иначе можно еще тип параметру явно указать, перед значением, и значит "автоопределением" из варианта.
-
ну, хоть на расстрел набежали, и то радует повторюсь, проблема не в том, что что-то не работает, а в том, что всё работает. @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 + ';');
try
Qry.Open;
for j := 0 to Qry.RecordCount-1 do begin
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) + '*)';
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;
end;
if QCash = 3 then
Grid.CellStyle[i, Zal].BGColor := clSetka else
Grid.CellStyle[i, Zal].BGColor := clZal; Qry.Next;
Application.ProcessMessages;
end;
except
on E: Exception do
ShowMessage(E.Message + #13#10 + Qry.SQL.Text);
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);
Result:=chr($27)+s+chr($27);
end;
end;
вот, так есть. всё работает. ошибка возникает, если выбрать дату в tdatetimepicker мышкой.
-
> fd2sql (c) Белов Владимир
Укуси меня пчела... О сколько раз твердили миру - используйте уже параметры.
З.Ы. Мне страшно ходить в кинотеатры.
-
Добавил Qry.ParamByName('ddate').asDateTime; чтобы совсем уж точно. То же самое.
-
не, не то же самое. Qry: Parameter 'ddate' not found - логично, ведь
for j := 0 to qry.Params.Count-1 do showmessage(qry.params[i].Name + qry.params[i].value); // !!
ничего не выдаёт но запрос-то работает!
-
> но, если > TDateTime(Trunc( datetimepicker.date))
Ты зачем так делаешь, вроде бы достаточно грамотный программист.
-
> что же мне указывать, если мне все поля нужны? перечислять > их все через запятую?
Ленивым не место в программирование.
-
Я имею некое представление про серверный курсор. При однонаправленном датасете мы можем лишь идти курсором вперёд по набору данных, используя .Next. Да, я понимаю, что раз он работает асинхронно, то я могу начать читать записи до того, как они все приедут по сети. Но как в таком случае мне отследить событие окончания приезда всех данных? Я положился на пример использования dbExpress, где так и было open - for .. recordcount - next - close - и всё работает.
-
> не, не то же самое. Qry: Parameter 'ddate' not found - логично, > ведь
А зачем ты обращаешься к несуществующему параметру?
-
> Ты зачем так делаешь, вроде бы достаточно грамотный программист.
Ты его, похоже, с Мегавольтом путаешь.
> Добавил Qry.ParamByName('ddate').asDateTime; чтобы совсем > уж точно. То же самое.
Всё, я так больше не могу. Это, походу, развод чей-то.
-
> А зачем ты обращаешься к несуществующему параметру? я к нему не обращаюсь. это я пробовал [21], [24]
-
> Но как в таком случае мне отследить событие окончания приезда > всех данных? Я положился на пример использования dbExpress, > где так и было open - for .. recordcount - next - close > - и всё работает.
Буратино был тупой,
Буратино был тупой,
Буратино был тупой,
Буратино был тупой,
Тупой как дрова,
Тупой как дрова,
Тупой как дрова,
Тупой как дрова
(с) Псой Короленко.
-
> сделал сразу же, результат в [8] там нет результата, там уверения "все правильно". вот если бы были приведены варианты ответов, с мышкой(ошибка) и без(ок), вот тогда "результаты".
> перечислять их все через запятую? именно так рекомендуется в любом мануале любого (пока не встречал исключений) sql сервера.
> вот тот самый метод полностью жуть. как сценарист ужастиков не пробовался? :)
во первых параметры во вторых for j := 0 to Qry.RecordCount-1 do ??? в третьих определение по имени поля внутри цикла в четвертых нет дизейбла контролов (датасет/стринггрид) в пятых ошибки вести в лог, и разделять в каком блоке произошли, абсолютно одинаковые не информативны. в шестых Application.ProcessMessages; в цикле позволяет извне выполнить "левые" операции, например закрытие/перезапрос запроса, т.к. сам "кверик" - глобальная переменная (экономишь?), где проверка после него? в седьмых сама "идея" перекладки в стрингрид бред. ну и в восьмых код без применения "советов", нафига он нужен? убедить нас что все правильно?
-
гм, признаю, я лох стоило заменить for j := 0 to Qry.RecordCount-1 do begin на while not Qry.Eof do begin И всё стало прекрасно. Никакой больше ошибки. Только по-прежнему непонятно, почему возникала - даже если предположить, что recordcount в текущий момент возвращает количество записей меньшее, чем есть на самом деле, то меньше - не больше, и тогда бы я видел данные не полностью - а они были полностью.
-
14 часов, 33 поста. Может завязать отвечать на вопросы, раз ответы нафиг никому не нужны? И конкуренции меньше на рынке будет...
-
> Ты его, похоже, с Мегавольтом путаешь.
Не путаю, смотри пост 28
-
> Anatoly Podgoretsky © (15.12.10 12:34) [35] > > но, если > > TDateTime(Trunc( datetimepicker.date)) > Ты зачем так делаешь, вроде бы достаточно грамотный программист.
от отчаяния, когда перепробовал сначала много способов, логически более очевидных.
Ну вот не найду никак ту тему, жалко.. короче, ну дык и пишу же case Q.Params[i].DataType of ftDateTime: Q.Params[i].AsDateTime := P[i]; else Q.Params[i].Value := P[i]; вот все равно, просто trunc от startoftheday получался, что отличался
-
> megavoid (15.12.2010 12:39:40) [40]
Я не пристаю (с) Тайна третей планеты.
-
> Не путаю, смотри пост 28
пардон, спутал.
> Ну вот не найду никак ту тему, жалко.. > короче, ну дык и пишу же
параметры вручную прописывал, или по Paramcheck получил? просто с ручными у меня никогда никаких проблем не было, ни под MSSQL, ни под Postgres, ни под FB. Да, это более муторное занятие. Писанины больше. Но зато никаких проблем.
-
> 12 (15.12.2010 12:58:46) [46]
Загубишь ты так промышленность нашу.
-
@sniknik там есть результат. без(ок), с мышкой - получали мессаджбокс Qry: Field 'dtime' not found SELECT * FROM z WHERE ddate='2010-14-12'; [OK]
> именно так рекомендуется в любом мануале любого (пока не встречал исключений) sql сервера. И если на следующий день заказчик захочет добавить ещё одно поле в базу, придётся ходить и везде его приписывать? В других запросах, где мне требуются только отдельные поля, я указываю их. Если нужны все - ставлю *. Сервер MySQL гордо и одиноко стоит на core i5, 4 Гб, и по всем логам не напрягает процессор больше чем на 1% в час пик. Расширения не планируется, так что его не жалко.
> жуть. как сценарист ужастиков не пробовался? :) Обязательно попробую после этой трёхстраничной простыни ужасов :)
> во первых параметры ну сделаю я Qry.Params.Add(ddate=date); - это будет мне очень неудобно - sql запрос req конструируется разный, в разных местах, с разными параметрами
> во вторых for j := 0 to Qry.RecordCount-1 do ??? это да, я лох, уже догадался сам :)
> в третьих определение по имени поля внутри цикла это из области фильмов ужасов, ага, но - работает
> в четвертых нет дизейбла контролов (датасет/стринггрид) нет. юзеры всё равно ничего не успеют сделать, пока получаем данные сильно подозреваю, что тоже из ужастиков
> в пятых ошибки вести в лог, и разделять в каком блоке произошли, абсолютно одинаковые не информативны. модуль лога пишется, скоро будет
> Application.ProcessMessages; да, не подумал. Но извне, пока работает FillGrid, никаких сообщений не придёт - всё однопоточное. Разве что может быть вариант, когда юзер нажмёт обновить, и, не дождавшись, снова нажмёт обновить - тогда в qry получится полная каша. На практике такого не случалось ни разу.
> перекладки в стринггрид В полном соответствии с требованиями заказчика. Для справки, в этом же проекте совсем рядом есть DBGridы, прекрасно работающие - но перекладывать в стринггрид мне всё равно пришлось - вот отсюда и этот страхокод :)
> ну и в восьмых код без применения "советов", нафига он нужен? убедить нас что все правильно? всё применял, все они в коде, всем спасибо за ответы!
-
> megavoid (15.12.2010 13:29:50) [50]
Ну так нету же, правильно сообщает, там вообще никаких параметров нет.
-
> megavoid (15.12.2010 13:29:50) [50]
"И если на следующий день заказчик захочет добавить ещё одно поле в базу, придётся ходить и везде его приписывать?" Я уже говорил, что ленивым нечего делать в программирование. Тебе надо в менеджеры и чтобы кресло пошире.
-
> И если на следующий день заказчик захочет добавить ещё одно > поле в базу, придётся ходить и везде его приписывать? В > других запросах, где мне требуются только отдельные поля, > я указываю их. Если нужны все - ставлю *.
Вот теперь я, как администратор БД, беру и меняю порядок полей в таблице. Или, например, добавлю в данную таблицу блоб-поле, в которой битмап для каждой записи будет лежать. Метра так на 2. И теперь ты по своей * будешь тащить на каждый чих по 100 записей дополнительно 200 мегабайт картинок. Это первое. Второе: а тебе и так и так придётся переписывать. Добавлять fieldByName и заносить его в определённый столбец твоего StringGrid.
> это будет мне очень неудобно - sql запрос req конструируется > разный, в разных местах, с разными параметрами
скажи, а зачем такой изврат нужен? Ну, в смысле, один DataSet на всё приложение? Заведи себе их столько, сколько нужно. Аккуратно пропиши параметры. Выстави Prepared (скомпилируй заранее). Получишь афигенный выигрыш на скорости, проверено неоднократно.
> > в третьих определение по имени поля внутри цикла > это из области фильмов ужасов, ага, но - работает
Вот тут я со sniknik не согласен. FieldByName - в целом более правильное обращение. Fields[Index] - это только если ты строго уверен, что НД пришёл в строго определённом порядке полей. Что сильно повышает неустойчивость в случае, если работаешь с хранимой процедурой, а её код может кто-то модифицировать.
> нет. юзеры всё равно ничего не успеют сделать, пока получаем > данные > сильно подозреваю, что тоже из ужастиков
Зря подозреваешь. Смотри код TDataSet. Года 2.5 -3 назад аккурат на этом форуме я вопрос поднимал. Простейшая операция disable|enable controls дала прирост производительности то ли в 30 раз, то ли в 70.
> Но извне, пока работает FillGrid, никаких сообщений не > придёт - всё однопоточное.
Да ну? Ты, видать, плохо разбираешься, что такое Application.ProcessMessages. простой пример. У тебя, запрос, который выполняется 5 секунд (это только Open). За эти 5 секунд ты наделал кучу всякой разной фигни мышкой. Что будет - предлагаю тебе самому на чистом проекте испытать.
-
> Вот тут я со sniknik не согласен. FieldByName - в целом более правильное обращение. Fields[Index] - это только если ты строго уверен не выдумывай отсебятины... Fields[Index] я сам нигде не использую и другим не советую. > в третьих определение по имени поля внутри цикла где тут Fields[Index]? здесь про "внутри цикла", вынести "за" и все дела, а не менять на что то самопридуманное.
-
> не выдумывай отсебятины... Fields[Index] я сам нигде не > использую и другим не советую.
Тогда я тебя не понял. Поясни "в третьих определение по имени поля внутри цикла"
-
> Поясни "в третьих определение по имени поля внутри цикла" > вынести "за" и все дела
-
> Вот теперь я, как администратор БД, беру и меняю порядок > полей в таблице. Или, например, добавлю в данную таблицу > блоб-поле, в которой битмап для каждой записи будет лежать. > Метра так на 2.
В данном конкретном случае администратор БД управляется мной же, и я просто не пропущу большой блоб. Когда это писалось, я закладывался на полный контроль всего комплекса со стороны меня, что и позволяет мне достаточно вольно писать мой говнокод, точно помня что, где и как расположено.
> скажи, а зачем такой изврат нужен? Ну, в смысле, один DataSet > на всё приложение?
Экономия, всё верно выше подметили. Над завести много датасетов - подумаю.
> Простейшая операция disable|enable controls дала прирост > производительности то ли в 30 раз, то ли в 70.
Прописал disable/enable. На глазок по скорости выполнения то же самое, но глазок не профайлер, вечером замерю без и с disablecontrols.
> Application.ProcessMessages
Там только ради WM_PAINT. Не 5, а 2-3 секунды :) WinSight у меня частенько открыт. Ну, даже если придёт LBUTTONDOWN или CLOSE - как это собьёт мне Query? Если пришлют DESTROY - ну тут и так понятно что хана, никакой квери уже нафиг не нужен будет.
ЗЫ. А кресло у меня большое-большое, ага :) А программирование мне больше по душе :)
-
> > вынести "за" и все дела Куда "за"? Оно потому и внутри цикла, что я получаю данные из полей в цикле.
-
> Ega23 (15.12.2010 13:54:53) [53]
Ты где такие маленькие битмапы нашел.
-
> Ega23 (15.12.2010 13:54:53) [53]
"Fields[Index] - это только если ты строго уверен, что НД пришёл в строго определённом порядке полей." Уверенность надо обретать в явном указание полей, а тогда можно и Fields[i]
-
> megavoid (15.12.2010 14:16:57) [57]
" и я просто не пропущу большой блоб." Не зарекайся. Кроме того все ты не проконтролируешь, на нормальных фирмах это разделено между разными людьми, и первому человеку совсем не обязательно знать, что админ добавил blob поле. Не его это дело, его дело писать правильные запросы, а не лениться. Молчу уж про параметры и оптимизатор.
-
> Уверенность надо обретать в явном указание полей, а тогда > можно и Fields[i] Ага, укажу я поля в запросе явно, а SQL обязан мне их в таком же порядке вернуть? Я уж лучше через .FieldByName. А то и вообще Ega23 придёт и порядок полей поменяет, а с fieldbyname мне это фиолетово.
-
> Куда "за"? Оно потому и внутри цикла, что я получаю данные из полей в цикле. за цикл, и не получение данных, а определение по имени. блин. что так сложно понять, до цикла определить поле и запомнить его в переменную, в цикле использовать ее.
> Прописал disable/enable. На глазок по скорости выполнения то же самое, но глазок не профайлер, вечером замерю без и с disablecontrols. на ста записях заметно не будет, вот сто тысяч... другое дело. + главный "тормоз" будет/есть не в нем а в стринггриде. и даже если ему поставить "дизебле" (там как то по другому называется) на обновления, это тоже будет мелочь по сравнению с тем как он сам по себе тормозит. "из принципа" (по логике с которой сделан)
-
> Ага, укажу я поля в запросе явно, а SQL обязан мне их в таком же порядке вернуть? да. хотя это и "всплыло" от не рекомендованного тут метода.
-
> В данном конкретном случае администратор БД управляется > мной же, и я просто не пропущу большой блоб. Когда это писалось, > я закладывался на полный контроль всего комплекса со стороны > меня, что и позволяет мне достаточно вольно писать мой говнокод, > точно помня что, где и как расположено.
Дык нету у тебя полного контроля при *, пойми. Полный контроль - когда ты чётко выбираешь именно те поля, которые тебе нужны. В том самом порядке, который тебе нужен. > Экономия, всё верно выше подметили. Над завести много датасетов > - подумаю.
Ты не на том экономишь. Если аналогию провести, то ты сейчас экономишь на мусорных пакетах, выбрасывая всё что есть в один, а потом на мусорке его разгребать и по разным контейнерам складывать: туда - пищевые отходы, туда - стекло всякое и т.д. Впрочем, это был ещё один совет. :))) > Прописал disable/enable. На глазок по скорости выполнения > то же самое, но глазок не профайлер, вечером замерю без > и с disablecontrols.
Может и не дать, тут очень многое зависит непосредственно от компонента. Надо реализацию смотреть. Но в целом - надо писать, это правило хорошего тона. > Там только ради WM_PAINT. Не 5, а 2-3 секунды :) WinSight > у меня частенько открыт. Ну, даже если придёт LBUTTONDOWN > или CLOSE - как это собьёт мне Query?
А ты возьми, зацепи окно мышкой и не отпускай. Потаскай его по экрану. Screen.Cursor := crSQLWait;
try
with DataSet do
begin
Open;
........
end;
finally
Screen.Cursor := crDefault;
end;
-
>>Кроме того все ты не проконтролируешь, на нормальных фирмах это разделено между разными людьми, и первому человеку совсем не обязательно знать, что админ добавил blob поле. Не зарекаюсь, но с 99.999% вероятностью на протяжении жизни этого проекта админ не будет трогать бд.
-
> Ага, укажу я поля в запросе явно, а SQL обязан мне их в > таком же порядке вернуть?
Естественно. Также, как и то, что сервер тебе произвольный порядок самих записей может выдать, если ты явно Order By не указал. На одинаковом запросе. > + главный "тормоз" будет/есть не в нем а в стринггриде. > и даже если ему поставить "дизебле" (там как то по другому > называется)
По всей видимости StringGrid1.Rows.BeginUpdate\EndUpdate проверять лениво.
-
> megavoid (15.12.2010 14:27:02) [62]
Ты даже не преставляешь как SQL работает, да именно обязан. Какой "Ega23 придёт и порядок полей поменяет" тебе порядок полей в твоей программе поменяет, окстись.
-
> sniknik (15.12.2010 14:28:03) [63]
На stringgrid можно много выиграть, очень медленный компонент.
-
> Не зарекаюсь, но с 99.999% вероятностью на протяжении жизни > этого проекта админ не будет трогать бд.
А ты не допускаешь мысли, что кроме данного проекта ты в своей жизни ещё и другими будешь заниматься? Где данное разделение будет в порядке вещей? Учись писать правильно с самого начала. Тебе не вредные советы дают, тут люди не один такой "кинозал" написали, а по десятку (если не больше).
-
> sniknik (15.12.2010 14:29:04) [64]
А я и не рекомендовал, просто указал, что и это надежный метод при правильном написание, а не при SELECT * В контексте необходимости явного указания полей.
-
> а не при SELECT *
А чё вы все DML-команды в UPPER CASE пишете? Это так, оффтопик...
-
> Ega23 (15.12.2010 14:29:05) [65]
Конечно рекомендации, ничего и другого в форуме не остается, ведь уволить то его за непрофессионализм мы не можем.
-
> megavoid (15.12.2010 14:32:06) [66]
Живо предание, я столько полей добавил в посторонние базы, они мне просто нужны, и что ты думаешь я оповещал разработчиков, правда и они на меня тоже плевали, поля типа bit собаки постоянно переделывают в shortint (у них "ошибка" в программах обновления). Вот так и боремся с друг другом.
-
> Ega23 (15.12.2010 14:42:12) [72]
Я пишу так как мне удобно, а удобно мне в Borland Pascal стиле. То есть каждое слово с большой буквы и без соокращений, кроме редких случаев. Я не боюсь много букав.
-
> поля типа bit собаки постоянно переделывают в shortint > (у них "ошибка" в программах обновления).
Ну дык. shortint в стандарте есть. bit - нету. :) Даже, ЕМНИП, byte (tinyint) нету.
-
> а удобно мне в Borland Pascal стиле.
Тогда почему SELECT, а не Select?
-
> А чё вы все DML-команды в UPPER CASE пишете? > Это так, оффтопик... ну сравни SELECT username,usertype,priority FROM sysusers WHERE username LIKE '%ix' select username,usertype,priority from sysusers whwere username like '%ix'
+ "Query Analyzer"/Access так генерит, т.е. можно считать стандарт.
-
Уж не один год пишу, много кинозалов получалось, какие-то хорошие, какие-то не очень. Ко всем советам стараюсь прислушиваться. Вот с базой - впервые у меня проект, отсюда много непониманий. За последние сутки узнал про SQL больше, чем за месяц чтения мануалов. Про * и поля понял, укажу их по порядку. Хотя админ НЕ будет их трогать.
Да, у грида beginupdate/endupdate, как и у listview. В listview выигрыш по скорости заметен на глаз уже при 500 записях. Кстати, при каком-то стиле listview ведёт себя как и датасет, тоже показывает и подгружает только то, что на экране.
-
> Ega23 (15.12.2010 14:47:16) [76]
Дело не в стандарте, дело происходит на MS SQL а разработчик поддерживает две системы одновременно MS SQL и Акцесс, где такого типа нет, поэтому я и взял в кавычки, но почему они гады не ограничиваются своими полями и лезут в мои собственные, видимо немного схалтурили, упростили себе жизнь. По идее надо бы было переделать программу, но больно удобен bit
-
> Ega23 (15.12.2010 14:48:17) [77]
Потому что я также и формат SQL поддерживаю, ключевые слова SQL писать с большой буквы, я не хочу лезть в чужой монастырь, а вот мои поля - мое дело. А их ключевые слова не мое. И читать в таком варианте удобно, тем более что я не пишу в одну строку, а во множество и с отступами.
-
> Кстати, при каком-то стиле listview ведёт себя как и датасет, тоже показывает и подгружает только то, что на экране. в "стиле" ручной отрисовки наверное, с хранением в своих структурах.
-
> megavoid (15.12.2010 14:52:19) [79]
Опять ты в угадайку играешь. Не важно будет он трогать или нет, ты не должен об этом знать, это не твое, ты просто обязан писать правильно, чтобы действия третьих сторон, тебя не затрагивали.
-
> Хотя админ НЕ будет их трогать.
Завтра возьмут на работу админа - и он будет их трогать.
-
> ну сравни > SELECT username,usertype,priority FROM sysusers WHERE username > LIKE '%ix' > select username,usertype,priority from sysusers whwere username > like '%ix'
У меня цветом выделяются.
-
> У меня цветом выделяются. в access? зависишь от инструментов.
-
> в access?
Не, с ним не работаю. Но в целом понял. Я всё в LowerCase начал писать, когда с Postgres-ом поработал. Там есть особенности case.
-
> Ega23 (15.12.2010 15:21:25) [85]
У меня в блокноте все черное, в Дельфи есть варианты
-
> У меня в блокноте все черное
Блокнот 300 лет уже не использовал. Только notepad++. Впрочем, это злостный оффтопик пошёл.
-
> Ega23 (15.12.2010 15:45:29) [89]
Ну и какая разница, тот же блокнот, немного различается. Профессионалу цвет только мешает. Он начинает думать, что этот зеленый знает, а красный.
-
вывод -> надо в дальтоники переходить
|