Справочник функций

Ваш аккаунт

Войти через: 
Забыли пароль?
Регистрация
Информацию о новых материалах можно получать и без регистрации:

Почтовая рассылка

Подписчиков: -1
Последний выпуск: 19.06.2015

DBgrid c сортировкой столбцов

18K
10 октября 2006 года
maestro_ufa
11 / / 10.10.2006
Есть DBGrid, куда загружаются данные достаточно ресурсоемкого запроса. Требуется реализовать сортировку грида по клику на заголовок столбца. Гонять каждый раз запрос к серверу с дописанным в конце ORDER BY - не вариант, т.к. будет выполняться достаточно долго. В голову приходит вариант загрузки данных в массив, где их потом сортировать. Но как тогда потом можно данные из отсортированного массива залить в DBGrid?
Или есть какой-то другой способ?
3.0K
10 октября 2006 года
Мerlin
267 / / 25.07.2006
Есть еще TClientDataSet.
294
11 октября 2006 года
Plisteron
982 / / 29.08.2003
Э... EhLib?
547
11 октября 2006 года
Hydra
488 / / 20.06.2006
Если сортировка не по вычисляему столбцу - индексы в руки и вперед, иначе скорее всего вьюсы.
309
11 октября 2006 года
el scorpio
1.1K / / 19.09.2006
Можно решить "в лоб".
Результат запроса не выводить в DBGrid, а записать в массив массивов строк. После этот массив записывать в обычный StringGrid.
При выборе способа сортировки, производится пересортировка массива в ОЗУ с последующим заполнением StringGrid'а
547
11 октября 2006 года
Hydra
488 / / 20.06.2006
А если записей дофига и больше - это ж БД и проектировать запросы надо исходя из этого.
309
11 октября 2006 года
el scorpio
1.1K / / 19.09.2006
[QUOTE=Hydra]А если записей дофига и больше - это ж БД и проектировать запросы надо исходя из этого.[/QUOTE]
Сама БД может и иметь записей "дофига", но результат SQL-запроса будет ограниченным.
Так что, если критерии отбора будут широкими, то проще будет повторить запрос с иной сортировкой. Если же притерии опроса жёсткие, позволяющие отобрать сравнительно небольшое кол-во записей - быстрее будет произвести повторную сортировку уже полученного результата.
547
11 октября 2006 года
Hydra
488 / / 20.06.2006
SQL запрос даст все записи, только результат выдается порциями, по требованию. А для загрузки в список придется получить сразу и все
16K
11 октября 2006 года
Миshук
5 / / 11.04.2006
[QUOTE=maestro_ufa]Есть DBGrid, куда загружаются данные достаточно ресурсоемкого запроса. Требуется реализовать сортировку грида по клику на заголовок столбца. Гонять каждый раз запрос к серверу с дописанным в конце ORDER BY - не вариант, т.к. будет выполняться достаточно долго. В голову приходит вариант загрузки данных в массив, где их потом сортировать. Но как тогда потом можно данные из отсортированного массива залить в DBGrid?
Или есть какой-то другой способ?[/QUOTE]Для варианта ADOQuery+DBGrid:
Код:
void __fastcall TForm1::DBGrid1TitleClick(TColumn *Column)
{

      if(Column->Title->Caption == "FatherName")
      {

        ADOQuery1->Sort = "";
        ADOQuery1->Sort = "FatherName ASC,CardNumberID";
      }
      else if(Column->Title->Caption == "CardNumberID")
      {

        ADOQuery1->Sort = "";
        ADOQuery1->Sort = "CardNumberID ASC,FatherName";
      }

}
3.0K
11 октября 2006 года
Мerlin
267 / / 25.07.2006
Оптимальный вариант: TClientDataSet.
309
11 октября 2006 года
el scorpio
1.1K / / 19.09.2006
[QUOTE=Мerlin]Оптимальный вариант: TClientDataSet.[/QUOTE]
Чем оптимален?
[QUOTE=Hydra]SQL запрос даст все записи, только результат выдается порциями, по требованию. А для загрузки в список придется получить сразу и все[/QUOTE]
SQL запрос выдаёт не "все" записи, а только те, которые соответствуют указанным условиям. Но их выдаёт не "порциями", а целиком, потому что его результат отделяется от содержимого таблиц БД.
10
11 октября 2006 года
Freeman
3.2K / / 06.03.2004
[QUOTE=Plisteron]Э... EhLib?[/QUOTE]
У него, кстати, есть LocalSort.

[QUOTE=el scorpio]Если же притерии опроса жёсткие, позволяющие отобрать сравнительно небольшое кол-во записей - быстрее будет произвести повторную сортировку уже полученного результата.[/QUOTE]
Согласен. Для этого, кстати, совершенно неообязательно городить геморрой с StringGrid. Есть MemTableEh, например.

[QUOTE=el scorpio]Но их выдаёт не "порциями", а целиком, потому что его результат отделяется от содержимого таблиц БД.[/QUOTE]
Зависит от запроса и плана его выполнения сервером. Если для полного выполнения запроса не требуется получение всех строк на стороне сервера, курсор может выбираться частично, по мере прокрутки.

Как правило, если ORDER BY идет не по индексу, выполнение запроса требует единовременного получения всех строк на стороне сервера.

[QUOTE=Hydra]А если записей дофига и больше - это ж БД и проектировать запросы надо исходя из этого.[/QUOTE]
Подозреваю, что база не нормализована, особенно, если структура один в один скопирована из унаследованной (файловой) реализации.
3.0K
11 октября 2006 года
Мerlin
267 / / 25.07.2006
[QUOTE=el scorpio]Чем оптимален?[/QUOTE]
Тем оптимален, что после загрузки записей в TClientDataset,
если нужна сортировка напр. по полю field1, то для этого достаточно

ClientDataSet1->IndexFieldNames = "field1";

Если по полю field2, тогда

ClientDataSet1->IndexFieldNames = "field2";

При этом можно определить индексы, и тогда индексы будут строиться только один раз.

Плюсь еще, что данные выводятся с помощью TDBGrid.

А то что ты предлагаешь, TStringGrid, два больших минуса

1. Постоянная пересортировка при смене поля.
2. В нормальной программе, числа в столбцах должны быть выравнены справа, даты по-середине. В TStringGrid это нужно будет сделать вручную.
547
12 октября 2006 года
Hydra
488 / / 20.06.2006
[QUOTE=el scorpio]
SQL запрос выдаёт не "все" записи, а только те, которые соответствуют указанным условиям. Но их выдаёт не "порциями", а целиком, потому что его результат отделяется от содержимого таблиц БД.[/QUOTE]
Ага, у меня в бд результат запроса весит 3га и что-то я не замечал чтобы сервер все это мгновенно по сети в клиента кидал. Про транзакции слышал?
294
12 октября 2006 года
Plisteron
982 / / 29.08.2003
[QUOTE=Plisteron]Э... EhLib?[/QUOTE]
[QUOTE=Freeman]У него, кстати, есть LocalSort.[/QUOTE]
Так я об этом и говорю.
309
12 октября 2006 года
el scorpio
1.1K / / 19.09.2006
[QUOTE=Hydra]Ага, у меня в бд результат запроса весит 3га и что-то я не замечал чтобы сервер все это мгновенно по сети в клиента кидал. Про транзакции слышал?[/QUOTE]
3 ГИГАБАЙТА :eek:
"Ну и запросы у вас", - сказала БД и зависла

Вообще-то SQL придумали как раз для того, чтобы передавать по сети именно то, что требуется. А если нужно получать таблицу целиком - пользуйте Table.

А "транзакция" - это механизм логирования изменений для их отмены, на тот случай, если произойдёт сбой в работе, либо ещё какая-нибудь причина для прекращения ввода на полпути.
294
13 октября 2006 года
Plisteron
982 / / 29.08.2003
[QUOTE=el scorpio]3 ГИГАБАЙТА :eek:
А "транзакция" - это механизм логирования изменений для их отмены, на тот случай, если произойдёт сбой в работе, либо ещё какая-нибудь причина для прекращения ввода на полпути.[/QUOTE]

Не совсем правильно.
Транзакция - это логический блок, объединяющий одну или более операций в базе данных и позволяющий подтвердить или отменить результаты работы всех операций в блоке.

"Основное назначение транзакций в базе данных -- переводить её из одного согласованного состояния в другое. При фиксации изменений в базе данных гарантируется сохранение либо всех изменений, либо ни одного. Более того, выполняются все правила и проверки, обеспечивающие целостность данных." (с) Том Кайт, "Oracle для профессионалов".

Кстати, 3 гига для современной СУБД -- мелочь.
18K
13 октября 2006 года
maestro_ufa
11 / / 10.10.2006
Всем спасибо за ответы.
В данном случае я имел в виду не запрос, возвращающий большое число записей, а запрос выполняющий долго на сервере.
Сопоставив всю полученную информацию, я пришел вот к такому решению.
Для отображения данных я пользовался TDBGrigEh из библиотеки EhLib (действительно красивая и удобная таблица), для хранинея использовал структуру TDataSet - TDataSetProvider - TClientDataSet - TDataSource.

 
Код:
TDataSet* MySourceDs;  //Запрашивает данные у сервера SQL-запросом
TDataSetProvide* MyProvider;
TClientDataSet* MyClientDs; //Хранит и индексирует данные локально
TDataSource* MyDataSource;
TDbGridEh*  MyDbGrid;


Связываются эти объекты следующим образом:
 
Код:
MyProvider->DataSet=MySourceDs;
MyClientDs->ProviderName=MyProvider;
MyClientDs->Data=MyProvider->Data;
MyDataSource->DataSet=MyClientDs;
MyDbGrid->DataSource=MyDataSource;


Для обеспечения сортировки, необходимо определить индексы:
 
Код:
TIndexOptions opts;
opts << ixCaseInsensitive;

for (int i=0; i<MyDbGrid->FieldCount; i++)
{
MyClientDs->AddIndex(MyDbGrid->Fields->FieldName+"Index",MyDbGrid->Fields->FieldName,opts,"","",0);
}


Для того, чтобы нажимался заголовок грида, необходимо выставить в true свойство TitleButton у столбцов:
 
Код:
for (int i=0; i<MyDbGrid->FieldCount; i++)
{
TColumnTitleEh* l_Column;
l_Column=MyDbGrid->Columns->Items->Title;
l_Column->TitleButton=true;
}


Теперь ловим событие грида OnSort, и задаем там индекс для сортировки:
 
Код:
void __fastcall TMyFrm::MyDbGrid_OnSort(TObject *Sender)
{
TColumnEh* l_SortCol=MyDbGrid->SortMarkedColumns->Items[0];
MyClientDs->IndexName=l_SortCol->FieldName+"Index";
}
547
13 октября 2006 года
Hydra
488 / / 20.06.2006
[QUOTE=el scorpio]
3 ГИГАБАЙТА
"Ну и запросы у вас", - сказала БД и зависла
[/QUOTE]
:)
2maestro_ufa
Что-то как-то слшком навороченно. Может все же запрос не очень красивый.
309
13 октября 2006 года
el scorpio
1.1K / / 19.09.2006
[QUOTE=Plisteron]
"Основное назначение транзакций в базе данных -- переводить её из одного согласованного состояния в другое. При фиксации изменений в базе данных гарантируется сохранение либо всех изменений, либо ни одного. Более того, выполняются все правила и проверки, обеспечивающие целостность данных." (с) Том Кайт, "Oracle для профессионалов".

Кстати, 3 гига для современной СУБД -- мелочь.[/QUOTE]
Согласен много гигов данных - это мелочь. А вот подобный результат запроса - абсурд.
А насчёт определения транзакции - я сказал почти тоже самое, только простыми словами.

Кстати, чтобы произвести пересортировку уже полученного набора данных, достаточно задать поля для индексации для содержимого. Естественно, перед открытием нового запроса, индексацию нужно будет обнулить.
10
13 октября 2006 года
Freeman
3.2K / / 06.03.2004
[QUOTE=maestro_ufa]
Теперь ловим событие грида OnSort, и задаем там индекс для сортировки:[/QUOTE]
В последних версиях EhLib есть дополнительные модули, реализующие сортировку на OnSort автоматом. Модули зависят от используемой БД и должны подключаться вручную. Возможно, и для ClientDataSet есть.
18K
13 октября 2006 года
maestro_ufa
11 / / 10.10.2006
Я как раз и задал поля для индексации TClientDataSet'a. TDataSet никакую индексацию не предоставляет. Если знаете способ проще, то поконкретнее пожалуйста.
10
13 октября 2006 года
Freeman
3.2K / / 06.03.2004
[QUOTE=maestro_ufa]TDataSet никакую индексацию не предоставляет.[/QUOTE]
В EhLib есть папочка с модулями, реализующими автоматическую сортировку по нажатию на заголовок, забыл только их имена. Нечто вроде BdeUtilsEh, IBUtilsEh. В старых версиях EhLib все было свалено в кучу.

[QUOTE=maestro_ufa]Если знаете способ проще, то поконкретнее пожалуйста.[/QUOTE]
Если модуль существует:
 
Код:
uses
  CdsUtilsEh;

Если нет - написать его, глядя на подобные как пример. Это если резко желается что-то универсальное создать.
Реклама на сайте | Обмен ссылками | Ссылки | Экспорт (RSS) | Контакты
Добавить статью | Добавить исходник | Добавить хостинг-провайдера | Добавить сайт в каталог