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

Я хочу, чтобы набор результатов запроса к базе данных имел определенный порядок. Информация, которую я хочу заказать, не содержится в базе данных, а динамически генерируется в коде (поэтому я не могу использовать ORDER BY).

Есть ли способ отсортировать набор данных после выполнения запроса к базе данных? (Мне не нужен индексированный доступ, я хочу только перебирать все записи.)


person Heinrich Ulbricht    schedule 26.10.2011    source источник
comment
Какой тип набора данных вы используете?   -  person Linas    schedule 26.10.2011
comment
Колонка, которую вы хотите использовать для заказа, рассчитывается? (используя OnCalcFields)   -  person Cesar    schedule 26.10.2011
comment
@Cesar В настоящее время столбца нет, только алгоритм, который может вычислять вес для каждой записи на основе других данных в приложении. Этот вес является критерием сортировки.   -  person Heinrich Ulbricht    schedule 26.10.2011


Ответы (4)


Существует вероятность, что она имеет сходство с ответом Йенса (+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; 
person Mark Wilkins    schedule 26.10.2011
comment
Мне больше всего нравится это для больших наборов данных, потому что объем данных для передачи кажется наименьшим. Для небольших наборов данных я бы, вероятно, выбрал одно из решений CDS. - person Heinrich Ulbricht; 02.11.2011

С ClientDataset вы можете изменить порядок после выполнения. Настройки IndexFieldNames сортирует набор данных.

Вы можете найти здесь информацию о том, как подключить клиентский набор данных к другому набору данных в том же приложении.

  object DataSetProvider1: TDataSetProvider
    DataSet = MyAdsQuery
    Left = 208
    Top = 88
  end
  object ClientDataSet1: TClientDataSet
    Aggregates = <>
    Params = <>
    ProviderName = 'DataSetProvider1'
    Left = 296
    Top = 88
  end
person Arjen van der Spek    schedule 26.10.2011
comment
Хорошая идея, но это скопирует все мои данные на CDS. Так что это вариант для небольших наборов данных. - person Heinrich Ulbricht; 02.11.2011

Насколько мне известно, единственный надежный способ сортировки набора данных — использовать ORDER BY.

Я бы:

  1. Добавьте в запрос фиктивное поле order_tag.
  2. Сбросить результаты во временную таблицу.
  3. Объявите курсор для перебора временной таблицы и установите order_tag, используя собственную логику и операторы UPDATE #temp_table.
  4. Выберите данные из временной таблицы и упорядочите по полю тега.
person Jens Mühlenhoff    schedule 26.10.2011
comment
То есть на стороне сервера, вы, конечно, можете изменить порядок и на стороне клиента, как предполагают некоторые другие ответы. - person Jens Mühlenhoff; 27.10.2011
comment
+1 Идея мне нравится, потому что я не хочу переносить все данные сразу на CDS. Ответ Марка делает еще один шаг вперед, не копируя все данные во временную таблицу. - person Heinrich Ulbricht; 02.11.2011

Основная хитрость здесь заключается в использовании поля Internal calc (FieldKind = fkInternalCalc), если они поддерживаются вашим подклассом TDataset. Если это не так, используйте TClientDataset в качестве промежуточного звена.

ДФМ:

object ClientDataSet1SortField: TIntegerField
  FieldKind = fkInternalCalc
  FieldName = 'SortField'
end

па:

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;
person Gerry Coll    schedule 27.10.2011