создать отчет

отредактировано December 2005 Раздел: FastReport 3.0
нужно создать отчет вида:
дата         номинал   кол-во  сумма
01.01.01        50          20         1000
                  ---------------------------
                             20         1000

02.02.02        5          4            20
                 100        2            200
                 --------------------------
                             6            220
с этим проблем нет,но дальше нужно по этому отчету подвести итоги следующего вида:
                   5            4            20
                   50          20            1000
                   100         2             200
то есть нужно изменить порядок сортировки (в первом отчете сначала по дате, потом по номиналу, а тут нужно только по номиналу)..

как можно это сделать с помощью одного запроса к БД??

запрос,к примеру:
select * from CardSales
order by CardSales.DateSale, CardSales.CardValue;

или
select DealerAccNum, Count(CardValue), CardValue, SUM(CardValue), DateSale from CardSales
group by DealerAccNum, DateSale, CardValue
order by DealerAccNum, DateSale, CardValue;

заранее спасибо..

Комментарии

  • gpigpi
    отредактировано 18:20
  • отредактировано 18:20
    спасибо, но пользовательские функции использовать нельзя, потому что отчет будет связан с паскалевским кодом..

    как сделать это средствами FR? понимаю,что производительность пострадает
  • sdlsdl
    отредактировано 18:20
    Структура таблиц какая?
  • отредактировано 18:20
    да тут с одной таблицей разобраться хотя бы
    CardSales:

    DateSale CardValue DealerAccNum

    в случае первого запроса получаем все записи,отсортированные по DateSale и потом по CardValue и в отчете использую Groupheader/footer

    во втором агрегатные ф-ии в запросе
  • sdlsdl
    отредактировано 18:20
    В отчете вижу 4 поля как минимум: "дата", "номинал", "кол-во", "сумма". А в таблице - 3. Поля для отчета откуда берутся? Вообще, в чем вопрос? Как выглядит запрос, который вернет данные для второго отчета?
  • отредактировано December 2005
    количество подсчитывается в отчете ф-ей COUNT
    а сумма = Count() * CardValue

    вопрос в том,что сначала группировка идет по дате
    и нужно перегруппировать по cardvalue без второго запроса к БД

    то есть оба отчета строятся на базе одного запроса, и как сделать второй отчет не ясно

    gpi, вопрос к тебе..ты писал,что делал средствами FR.. please
  • sdlsdl
    отредактировано 18:20
    Честно говоря, не вижу причин для отказа от еще одного запроса. Пересортировать данные в первом простым способом вряд получится, не говоря уже о том, что сама структура выборки данных в них слишком разная. Для того нам и дан SQL. Или еще один запрос - слишком "дорогая" операция?

    Вот:

    SELECT CardValue, COUNT(*), SUM(CardValue)
    FROM CardSales
    GROUP BY CardValue
    ORDER BY CardValue
  • отредактировано 18:20
    естественно мне тоже первое,что пришло в голову и самое просто - второй запрос
    и да, операция слишком дорогая по времени
  • sdlsdl
    отредактировано 18:20
    Если запрос будет выглядеть точно так, как я написал, в таблице нужен индекс по CardValue. А вообще, порядок полей в GROUP BY должен соответствовать порядку полей в составном индексе. Тогда этот запрос будет работать быстро.
  • отредактировано 18:20
    второй запрос не подходит
    запрос должен быть один,такое условие
  • отредактировано December 2005
    1)Какие компоненты доступа используешь?

    Для DBX например, могу посоветовать доработать клиентский набор TfrxDBXDataset, добавив ему метод для задания индекса(ну или создать свой). Этот индекс строится в памяти и повторные запросы к базе не производятся.

    2) Создай StringList и руками заноси туда итоговые строки, он тебе отсортирует, главное только помнить что строки надо дополнять слева для нормальной сортировки. Потом просто вывести так же как из любого массива.
  • gpigpi
    отредактировано 18:20
    dimm
    Попробуй перевести мой способ на FS. От записей придётся отказаться, а динамические массивы в FS вроде бы уже поддерживаются.
    Сегодня вечером и сам попробую сделать без использования пользовательских функций.
  • gpigpi
    отредактировано 18:20
    Вот, получилось. Только средствами FS
    var ListSchet, ListSum: TStringList;
        SchetArray: array of string;
        SummaArray: array of extended;
    
    procedure SortToBalansSchet(Switch:Integer; Schet: String; Summa: Extended);
    var i, position, len: integer;
        UpdateSchetArray: Boolean;
    begin
      if Switch=0 then
         begin
             ListSchet:=TStringList.Create;
             ListSchet.Sorted:=True;
             ListSum:=TStringList.Create;
             ListSum.Sorted:=False;
             SetLength(SchetArray,0);
             SetLength(SummaArray,0);
           end;
        if Switch=1 then
         begin
             UpdateSchetArray:=False;
             for i:= 0 to length(SchetArray)-1 do
               if SchetArray[i]=schet then
                 begin
                   SummaArray[i]:=SummaArray[i]+Summa;
                   UpdateSchetArray:=True;
                   break;
                 end;
             if not UpdateSchetArray then
               begin
                 SetLength(SchetArray,length(SchetArray)+1);
                 SetLength(SummaArray,length(SummaArray)+1);
                 SchetArray[length(SchetArray)-1]:=Schet;
                 SummaArray[length(SummaArray)-1]:=Summa;
               end;
           end;
        if Switch=2 then
         begin
             ListSchet.Clear;
             ListSum.Clear;
             for i:=0 to length(SchetArray)-1 do
               begin
                 ListSchet.Add(SchetArray[i]+'|'+FormatFloat('# ### ##0.00',SummaArray[i]));
               end;
             ListSchet.Sorted:=False;
             for i:=0 to ListSchet.Count-1 do
               begin
                 position:=Pos('|',ListSchet.Strings[i]);
                 len:=length(ListSchet.Strings[i]);
                 ListSum.Add(copy(ListSchet.Strings[i],position+1,len-position));
                 ListSchet.Strings[i]:=copy(ListSchet.Strings[i],1,position-1);
               end;
             Set('Schet',ListSchet.Text);
             Set('Summa',ListSum.Text);
             ListSchet.Free;
             ListSum.Free;
             SetLength(SchetArray,0);
           end;
    end;
    
    procedure MasterData1OnBeforePrint(Sender: TfrxComponent);
    begin
         SortToBalansSchet(1,<ReportDataset1."BALANS_KOD">,<ReportDataset1."SUMMA">);
    end;
    
    procedure GroupFooter1OnBeforePrint(Sender: TfrxComponent);
    begin
         SortToBalansSchet(2,'',0);
    end;
    
    procedure GroupHeader1OnBeforePrint(Sender: TfrxComponent);
    begin
         SortToBalansSchet(0,'',0);
    end;
    
  • отредактировано 18:20
    Спасибо!
    на всякий случай,если вдруг просто не заметил, еще туда:
    SetLength(SummaArray,0);
  • gpigpi
    отредактировано 18:20
    Да, SetLength(SummaArray,0) я пропустил. Спасибо.
  • отредактировано December 2005
    gpi, у меня опять к тебе вопрос на ту же тему ;)
    у нас сортировка ведь происходит, как будто мы сортируем строки, а не числа. так,например, 100 получается меньше 20

    TStringList.CustomSort в fs не поддерживается (почему??!)

    что с этим делать?
  • gpigpi
    отредактировано 18:20
    Могу предложить два варианта:
    1) заносить числа в массив в формате '100', '020', '006', а при выводе убирать нули
    2) сортировку выполнять в массивах, в StringList заносить результат
    Я использую третий вариант: сказал пользователям, чтобы счета заносили с нулями ;)
  • отредактировано 18:20
    тогда вопрос к разработчикам:
    почему так бедно реализована функциональность TStringList?
  • отредактировано 18:20
    Сортировка средствами FS (разделитель - знак | ):
    procedure ExchangeItems(List:TStringList; i1, i2:Integer);
    var x:String;
    begin
      x:=List.Strings[i1];
      List.Strings[i1]:=List.Strings[i2];
      List.Strings[i2]:=x;
    end;
    
    procedure CustomSort(List:TStringList);
    var
      I, J, P: Integer;
      L, R: Integer;
    begin
      L:=0; R:=List.Count-1;
      repeat
        I := L;
        J := R;
        P := (L + R) shr 1;
        repeat
          while SortByVal(List, I, P) < 0 do Inc(I);
          while SortByVal(List, J, P) > 0 do Dec(J);
          if I <= J then
          begin
            ExchangeItems(List, I, J);
            if P = I then
              P := J
            else if P = J then
              P := I;
            Inc(I);
            Dec(J);
          end;
        until I > J;
        if L < J then CustomSort(List);
        L := I;
      until I >= R;
    end;
    
    function SortByVal(List: TStringList; Index1, Index2: Integer):Integer;
    var position:Integer;
    Val1, Val2:Extended;
    begin
    position:=Pos('|',List.Strings[Index1]);
    Val1:=StrToFloat(Copy(List.Strings[Index1], 0, position-1));
    
    position:=Pos('|',List.Strings[Index2]);
    Val2:=StrToFloat(Copy(List.Strings[Index2], 0, position-1));
    
    if Val1<Val2 then Result:=-1 else
      if Val1=Val2 then Result:=0 else
                        Result:=1;
    end;
    

    ну и
    ListVal.Sorted:=False;
     for i:=0 to length(ValArray)-1 do
             begin
                ListVal.Add(FormatFloat('##.#', ValArray[i])+'|'+IntToStr(CountArray[i]));
              end;
            CustomSort(ListVal);
    
  • отредактировано 18:20
    у нас используется tfrxReportServer

    если всё-таки используем внешнюю функцию, то что написать вместо
    Report_3.Variables['Schet']:=ListSchet.Text;
    Report_3.Variables['Summa']:=ListSum.Text;
    

    то есть, как обратиться к переменным отчета?
    есть ли вообще такая возможность?

Оставить комментарий

Многофункциональный текстовый редактор. Чтобы отредактировать стиль параграфа, нажмите TAB, чтобы перейти к меню абзаца. Там вы можете выбрать стиль. По умолчанию не выбран ни один стиль. Когда вы выберете текст, появится встроенное меню форматирования. Нажмите TAB, чтобы войти в него. Некоторые элементы, такие как многофункциональные вставки ссылок, картинок, индикаторов загрузки и сообщений об ошибок могут быть вставлены в редактор. Вы можете перемещаться по ним, используя стрелки внутри редактора и удалять с помощью клавиш delete или backspace.