Версия для печати темы

Нажмите сюда для просмотра этой темы в обычном формате

Форум «Всё о Паскале» _ Делфи _ сортировка данных-?

Автор: 1147 2.11.2009 21:15

В таблице необходимо отсортировать данные по дате таким образом:
31.11.2002
02.07.2003
12.01.2004
07.12.2005
20.05.2006
использовал следующий код:

procedure TForm1.N8Click(Sender: TObject);
begin
DataModule1.BookTable.IndexFieldNames:= 'Дата';
end;
но он сортирует данные в таком порядке:
02.07.2003
07.12,2005
12.01.2004
20.05.2006
31.11.2002
т.е. сортировка происходит по первым числам а не по фактической величине даты. Пробовал таким образом:
procedure TForm1.N8Click(Sender: TObject);
begin
DataModule1.BookTable.sort:= 'Дата';
end;
но результат тот же самый. Подскажите, как правильно отсортировать данные по дате как описано выше

Автор: volvo 2.11.2009 21:25

Зачем тебе сортировать данные в таблице, если можно отсортировать их при отображении (в том же DBGrid-е, например)? Что за база? Способ подключения? Как описано поле "Дата"?

Автор: 1147 2.11.2009 21:32

данные в таблице нужно сортировать по дате в том случае, если была использована сортировка по фамилии, чтобы привести таблицу в исходное состояние. MS Access, ADO. Дата-widestring

Автор: volvo 2.11.2009 21:42

Цитата
Дата-widestring
Вот поэтому и не работает
Цитата
DataModule1.BookTable.sort:= 'Дата';
... Данные из поля "Дата" трактуются как строка (и сортируются как строка, заметь, совершенно правильно), а не как DateTime.

Еще раз: я не совсем понимаю, зачем надо сортировать ТАБЛИЦУ, а не ее отображение? Ну, смотри: есть у меня DBGrid, который отображает мои данные. По щелчку на заголовке пользователь хочет получить данные отсортированные по возрастанию имени. И что, мне из-за этого пересортировывать таблицы? Оно мне надо? А не проще поменять SQL Query для этого DBGrid-а на SELECT ... FROM ... ORDER BY 'Имя' ? А потом, когда надо привести данные в первоначальный вид - просто убрать ORDER BY.

В общем, единственное, что могу посоветовать - поменять тип поля на DataTime (как там он называется-то в Access-е?), чтобы сортировка (и по ORDER BY в том числе) работала правильно. И пересмотри то, как ты взаимодействуешь с базой, не надо лишних действий делать. База ни при чем, работай с отображением.

Автор: 1147 2.11.2009 22:55

Можно по-подробней про сортировку отображения данных? Для этого на форме нужен компонент SQL Query да? соединяем его с нужной таблицей, а дальше как?

Автор: volvo 3.11.2009 2:34

На форме лежит ADOQuery1, в поле SQL которой прописано: "SELECT * from table1" Она связана с DataSource, а к этому DataSource-у привязан DBGrid. Это начальная ситуация.

Теперь, допустим, мне надо сортировать данные по дате рождения. Что я делаю? Правильно, выполняю вот это:

  AdoQuery1.SQL.Clear;
AdoQuery1.SQL.Text := 'SELECT * from table1 order by DateOfBirth';
ADOQuery1.Open;

Этого достаточно, чтобы DBGrid стал показывать данные, отсортированные по возрастанию DateOfBirth. Что надо сделать, чтобы вернуться к изначальному состоянию? Правильно, поставить назад SELECT-запрос без части ORDER BY... Вот и все...

Автор: 1147 3.11.2009 3:08

После заполнения поля SQL - "SELECT * from table1" при попытке активировать ADOQuery возникает ошибка. В чем тут может быть дело?
И получается что для сортировки и возврата в изначальное состояние нужно воспользоваться например двумя кнопками да?


Эскизы прикрепленных изображений
Прикрепленное изображение

Автор: volvo 3.11.2009 3:22

Я надеюсь, ты вводишь запрос БЕЗ кавычек?

Автор: 1147 3.11.2009 3:31

no1.gif no1.gif
(наверное такой ответ может ввести в заблуждение-я действительно вводил с кавычками). Теперь вроде все правильно, вот только при нажатии кнопки, все данные из таблицы пропадают

Автор: volvo 3.11.2009 4:04

Цитата
И получается что для сортировки и возврата в изначальное состояние нужно воспользоваться например двумя кнопками да?
Хочешь - пользуйся кнопками. Мне удобнее повесить на щелчок по заголовку ДБГрида вот такой обработчик:
procedure TForm1.DBGrid1TitleClick(Column: TColumn);
var s: string;
begin
s := 'select * from table1 order by ' + Column.FieldName;

AdoQuery1.SQL.Clear;
AdoQuery1.SQL.Text := s;
ADOQuery1.Open;
end;
(в принципе, можно сделать еще какой-нибудь чекбокс, выбирающий направление сортировки), а вот для возврата в неотсортированное состояние воспользоваться кнопкой.

Добавлено через 59 сек.
Цитата
вот только при нажатии кнопки, все данные из таблицы пропадают
Значит, что-то не так делаешь... ничего не должно пропадать. Тем более из таблицы.

Автор: 1147 6.11.2009 5:21

после изменения типа "Дата" с widestring на data/time в MSAccess, перестал работать поисковый фильтр в программе по данным содержащимся в этом столбце. Фильтр построен таким образом:

procedure TForm1.Edit3Change(Sender: TObject);
begin
if Length(Edit3.Text) > 0 then begin
form1adotable1.Filtered := false;
form1.adotable1.Filter := '[Дата] LIKE *' + Form1.Edit3.Text + '*';
form1.adotable1.Filtered := true;
end
else
form1.adotable1.Filtered := false;
end;

Для полей типа data/time нужно по-другому организовывать условия поиска, или я ошибочно считаю что проблема в этом?

Автор: volvo 6.11.2009 6:16

Цитата
Для полей типа data/time нужно по-другому организовывать условия поиска
Естественно... LIKE работает именно с текстом, с датами работают при помощи других функций. Но "мы пойдем другим путем" (С):

1) OnChange Эдита чуть-чуть меняешь:
procedure TForm1.Edit1Change(Sender: TObject);
begin
if Length(Edit1.Text) > 0 then begin
ADOTable1.Filtered := false; // Отключаешь фильтрацию
ADOTable1.Filtered := true; // И тут же опять включаешь... Зачем - чуть ниже поймешь
end
else
ADOTable1.Filtered := false;
end;

2) А теперь - зачем нам понадобилось делать столь неразумно: отключать фильтр и тут же его опять включать, ничего не меняя. А вот зачем: есть у TADOTable такое событие - OnFilterRecord, в котором ты можешь задать для активного фильтра критерий, допускать ли запись или фильтровать ее. Вот для того, чтобы при каждом изменении содержимого Edit-а перефильтровывались данные, и надо отключить/включить Filtered. Ну, и сам обработчик:
procedure TForm1.ADOTable1FilterRecord(DataSet: TDataSet; var Accept: Boolean);
begin
Accept :=
Pos(Edit1.Text, DataSet.FieldByName('DateOfBirth').AsString) > 0;
end;
(я везде оставил свои названия компонентов, поменяешь потом на то, что у тебя...)

Теперь можно в Эдите набирать любые сочетания, хоть так: 10/10/ (что выдаст тебе все данные с датой = 10 октября), хоть вот так: /12/ (что покажет все декабрьские даты). Ну, в общем, как и LIKE smile.gif

Автор: 1147 6.11.2009 6:42

mega_chok.gif Спасибо!!

Автор: 1147 6.11.2009 8:45

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

procedure TForm5.IKEFilterRecord(DataSet: TDataSet; var Accept: Boolean);
begin
if edit1.Focused then
Accept :=
Pos(Edit1.Text, DataSet.FieldByName('DateOfBirth').AsString) > 0;
if edit2.Focused then
Accept :=
Pos(Edit2.Text, DataSet.FieldByName('Names').AsString) > 0;
end;

Но в этом случае, если я хочу найти имена, начинающиеся с большой буквы, то в поисковое поле я также должен вводить имя с большой буквы. При этом поиск отфильтровывает те же самые имена но начинающиеся с маленькой буквы. Т. е. необходимо учитывать регистр.
Как бы исправить эту ситуацию, ничего не потеряв при этом?

Автор: volvo 6.11.2009 13:40

Во-первых, не надо делать несколько условий. Дельфи позволяет всегда объединить их в одно. А во-вторых, Приводи обе сравниваемые строки к одному регистру, и сравнивай. Итого:

  Accept :=
(Edit1.Focused and (Pos(Edit1.Text, DataSet.FieldByName('DateOfBirth').AsString) > 0))
or
(Edit2.Focused and (Pos(AnsiLowerCase(Edit2.Text), AnsiLowerCase(DataSet.FieldByName('Names').AsString)) > 0));


Можешь использовать AnsiUpperCase вместо ...Lower...

Автор: andriano 6.11.2009 14:51

Цитата(volvo @ 6.11.2009 9:40) *

Во-первых, не надо делать несколько условий. Дельфи позволяет всегда объединить их в одно.
Ну, во-первых, не Делфи, а алгебра логики. Делфи просто поддерживает правила, принятые в этой математической дисциплине.
А во-вторых, тезис об объединении условий не может быть принят как универсальная рекомендация. В данном конкретном случае это оправдано, но внутри вложенного цикла я бы порекомендовал, наоборот, разделять условия, ставя в начало те, которые чаще всего НЕ будут выполняться (если их вычисление сравнимо по ресурсоемкости). Правильная компоновка условий может в отдельных случаях привести к экономии времени выполнения в тысячи раз.

Автор: volvo 6.11.2009 15:01

Цитата
А во-вторых, тезис об объединении условий не может быть принят как универсальная рекомендация.
А в третьих, разницу между тем, что процитировал ты и "Поскольку Дельфи позволяет объединить несколько условий в одно, то это нужно делать всегда" чувствуешь? Я не призывал (что ты мне приписываешь) использовать данный прием ВСЕГДА.

Я (в отличие от некоторых) говорю только о данном конкретном случае. Пространные рассуждения о "сферических конях в вакууме" (С) - не мой стиль... Всегда что-нибудь пойдет не так: либо вакуум не тот, либо конь не сферическим получится... Так что каждый случай разбирается отдельно.

Автор: andriano 6.11.2009 15:22

Цитата(volvo @ 6.11.2009 11:01) *
Так что каждый случай разбирается отдельно.
Ну именно так и надо было написать: "в данном случае я бы порекомендовал...".
Твоего авторитета достаточно, чтобы новички любое твое высказывание воспринимали как истину в последней инстанции. На все времена. И это откладывалось на подсозналке. А потом, возможно, через годы на каком-нибудь другом форуме человек будет искренне недоумевать, почему ему советуют разделить условия, тогда как он совершенно точно знает, что в Делфи их нужно, наоборот, объединять.
Как в программировании вообще, так и в каждом конкретном языке есть ряд правил, которых надо придерживаться ВСЕГДА, а есть ряд конкретных решений оптимальных для частной задачи. Так вот, хотелось бы, чтобы непосредственно из текста сообщения было ясно, к которому из этих двух случаев относится данное замечание.

Автор: 1147 6.11.2009 20:36

Цитата
Приводи обе сравниваемые строки к одному регистру, и сравнивай

Нет ли каких-нибудь других вариантов? С поиском теперь все в порядке, но при переходе в DBGrid для редактирования найденной записи, стоит только нажать кнопку, запись пропадает.
Хотя дело не в этом похоже. Если переходить в найденную запись с помощью мыши, все в порядке. У меня в Edit1 в событии OnKeyPress такой код:
if key=#13 then AdoTable1.FieldByName('Names').FocusControl;
Вот при использовании нажатия Enter при переходе в Dbgrid и начинает все пропадать.
Почему переход в DBGrid мышью и Enterом влечет за собой такие разные последствия?
Нет. с мышью тоже проблемы, похоже несоответствие гдето раньше(. Всетаки мне кажется что проблемы начались после приведения строк к одному регистру.
Все я совершенно запутался... Оставил только поиск по дате (а там без приведения к одному регистру), из DBGrida всеравно все пропадает

Автор: volvo 6.11.2009 21:45

Опять начинается то же самое... Это не из-за нововведений, у меня прекрасно отрабатывает:

procedure TForm1.Edit2KeyPress(Sender: TObject; var Key: Char);
begin
if Key = #13 then
begin
// Key := #0; // На всякий случай можно бы и это сделать
DBGrid1.SelectedField := DBGrid1.DataSource.DataSet.FieldByName('txt');
DBGrid1.SetFocus;
end;
end;
, а у тебя, как видно, еще что-то, что навешано, мешает нормальной работе обработчика. Здесь я бессилен... Надо во-первых иметь исходники проекта, чтобы найти причину. А во-вторых - время в них копаться. У меня нет ни первого ни второго...

Автор: 1147 8.11.2009 23:43

а можно всетаки использовать Edit для поиска даты без события OnFilterRecord? Пробовал DataTimePicker, но во-первых это не удобно, а во-вторых из-за замены компонента очень многое нужно переделывать в программе sad.gif
Еще можно в базе создать дополнительный столбец widestring, невидимый в программе, куда будет копироваться дата и производить поиск по этому столбцу, но мне кажется это не совсем корректно както

Автор: volvo 9.11.2009 0:52

Цитата
а можно всетаки использовать Edit для поиска даты без события OnFilterRecord?
Попробуй составить в Access-е SQL-запрос, который будет работать так, как тебе нужно, то есть, из таблицы выбирать дату, конвертировать ее в строковое представление, и только потом применять к полученному строковому представлению LIKE. Получится - значит перенесешь полученный фильтр в Дельфи, не получится - ... Ну, сам понимаешь smile.gif