#delphi #sorting #dataset #delphi-2009 #advantage-database-server
#delphi #сортировка #набор данных #delphi-2009 #преимущество -сервер базы данных
Вопрос:
Я хочу, чтобы результирующий набор запроса к базе данных имел определенный порядок. Информация, по которой я хочу упорядочить, не содержится в базе данных, а динамически генерируется в коде (поэтому я не могу использовать ORDER BY
).
Есть ли способ отсортировать набор данных после выполнения запроса к базе данных? (Мне не нужен индексированный доступ, я хочу только перебирать все записи.)
Комментарии:
1. Какой тип набора данных вы используете?
2. Вычисляется столбец, который вы хотите использовать для упорядочения? (с использованием OnCalcFields)
3. @Cesar В настоящее время нет столбца, только алгоритм, который может вычислять «вес» для каждой записи на основе других данных в приложении. Этот вес является критерием сортировки.
Ответ №1:
С помощью ClientDataSet вы можете изменить порядок после выполнения. Настройки IndexFieldNames сортирует набор данных.
Здесь вы можете найти информацию о том, как подключить clientdataset к другому набору данных в том же приложении.
object DataSetProvider1: TDataSetProvider
DataSet = MyAdsQuery
Left = 208
Top = 88
end
object ClientDataSet1: TClientDataSet
Aggregates = <>
Params = <>
ProviderName = 'DataSetProvider1'
Left = 296
Top = 88
end
Комментарии:
1. Хорошая идея, но это скопировало бы все мои данные на компакт-диски. Таким образом, это вариант для небольших наборов данных.
Ответ №2:
Существует вероятность, которая имеет сходство с ответом Йенса ( 1), но приводит к результату несколько иным образом.
Учитывая существующую таблицу:
create table somedata (id integer, name char(20));
insert into somedata values ( 1, 'Tim' );
insert into somedata values ( 2, 'Bob' );
insert into somedata values ( 3, 'Joe' );
Если вы знаете желаемый короткий порядок (либо путем обработки таблицы, либо какого-либо результата запроса из нее), создайте временную таблицу с некоторым значением ключа, соответствующим желаемым строкам из исходной таблицы, а затем данные порядка сортировки:
create table #sortorder( id integer, sortvalue integer );
Установите sortvalue
поле во временной таблице так, чтобы оно содержало желаемый порядок (это может быть любой сортируемый тип данных — не обязательно целое число):
insert into #sortorder values ( 1, 15 );
insert into #sortorder values ( 2, 12 );
insert into #sortorder values ( 3, 5 );
Затем сгенерируйте результаты с помощью объединения с таблицей, которая обеспечивает порядок сортировки:
select sd.* from somedata sd, #sortorder so
where sd.id = so.id
order by so.sortvalue;
Комментарии:
1. Мне это нравится больше всего для больших наборов данных, потому что объем передаваемых данных кажется наименьшим. Для небольших наборов данных я бы, вероятно, выбрал одно из решений CDS.
Ответ №3:
AFAIK единственный надежный способ сортировки набора данных — использовать ORDER BY
.
Я бы:
- Добавьте фиктивное
order_tag
поле в свой запрос. - Сбросьте результаты во временную таблицу.
- Объявите курсор для итерации по временной таблице и задайте
order_tag
, используя вашу пользовательскую логику иUPDATE #temp_table
инструкции. - Выберите данные из временной таблицы и упорядочите по полю тега.
Комментарии:
1. То есть на стороне сервера, вы, конечно, можете изменить порядок и на стороне клиента, как предполагают некоторые другие ответы.
2. 1 Мне нравится идея, потому что я не хочу передавать все данные сразу на компакт-диск. Ответ Марка делает еще один шаг вперед, не копируя все данные во временную таблицу.
Ответ №4:
Основной трюк здесь заключается в использовании внутреннего поля calc (FieldKind = fkInternalCalc), если они поддерживаются вашим подклассом TDataSet. Если это не так, используйте TClientDataSet в качестве промежуточного.
DFM:
object ClientDataSet1SortField: TIntegerField
FieldKind = fkInternalCalc
FieldName = 'SortField'
end
pas:
procedure TForm1.FormCreate(Sender: TObject);
begin
ADOConnection1.Open('dbuser', 'Hunter2');
ClientDataSet1.SetProvider(ADOQuery1); // set ClientDataset provider. This will create a TLocalAppServer provider "in the background"
ClientDataSet1.Open;
randomize;
while not ClientDataSet1.Eof do
begin
ClientDataSet1.edit;
ClientDataSet1SortField.AsInteger := random(100);
// as ClientDataSet1SortField is fkInternalCalc it doesn't need to be in the query result set, but can be assigned and used for sorting
ClientDataSet1.Post;
ClientDataSet1.Next;
end;
clientdataset1.IndexFieldNames := 'SortField';
end;