Персонализиран ред на сортиране за набор от данни след изпълнение на заявка?

Искам наборът от резултати на заявка към база данни да има определен ред. Информацията, по която искам да подредя, не се съдържа в базата данни, а се генерира динамично в код (така че не мога да използвам 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

AFAIK единственият надежден начин за сортиране на набор от данни е да се използва 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

Основният трик тук би бил да използвате поле за вътрешно изчисление (FieldKind = fkInternalCalc), ако те се поддържат от вашия подклас TDataset. Ако не са, използвайте TClientDataset като междинен.

DFM:

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