Пользовательский порядок сортировки для набора данных после выполнения запроса?

#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 .

Я бы:

  1. Добавьте фиктивное order_tag поле в свой запрос.
  2. Сбросьте результаты во временную таблицу.
  3. Объявите курсор для итерации по временной таблице и задайте order_tag , используя вашу пользовательскую логику и UPDATE #temp_table инструкции.
  4. Выберите данные из временной таблицы и упорядочите по полю тега.

Комментарии:

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;