1 (edited by m.prokhachev 2018-07-16 12:25:53)

Topic: Создание сложного отчета - алгоритм решения проблемы.

Почитав тут разные темы, решил обобщить все, что прочитал.

Итак, имеется потребность в создании сложного отчета, в котором вывод данных осуществляется из двух и более малосвязанных или несвязанных таблиц.

Шаг 1. Создание шаблона отчета (.fr3-файла). То есть надо вписать статический текст, разметить поля для вывода меняющихся данных (из БД), подготовить те же диаграммы для выводимых данных. Создание шаблона мною пока не изучено, интересовали пока следующие шаги.

Шаг 2. Создание скрипта, подготавливающего наборы данных и связывающий эти наборы с шаблоном отчета. По следующему шаблону:

procedure Employees_Button5_OnClick (Sender: string; var Cancel: boolean);
var
    frxDBDataset1, frxDBDataset2,frxDBDataset3: TfrxDBDataset;
    Employee, Email, Phone: TDataSet;
begin

SQLQuery('SELECT id, FirstName, Surname FROM Employees', Employee);
SQLQuery('SELECT id_Employees, emailaddress FROM email', Email);
SQLQuery('SELECT id_Employees, phonenumber FROM phone',  Phone);

 // create Employees
    frxDBDataset1 := TfrxDBDataset.Create(Employees);
    frxDBDataset1.UserName        := 'Employee';
    frxDBDataset1.CloseDataSource := True;
    frxDBDataset1.OpenDataSource  := True;
    frxDBDataset1.DataSet         := Employee;

    // create second Email
    frxDBDataset2 := TfrxDBDataset.Create(Email);
    frxDBDataset2.UserName        := 'Email';
    frxDBDataset2.CloseDataSource := True;
    frxDBDataset2.OpenDataSource  := True;
    frxDBDataset2.DataSet         := Email;

    // create phone
    frxDBDataset3 := TfrxDBDataset.Create(Phone);
    frxDBDataset3.UserName        := 'Phone';
    frxDBDataset3.CloseDataSource := True;
    frxDBDataset3.OpenDataSource  := True;
    frxDBDataset3.DataSet         := Phone;

    Employees.frxReport.Clear;
    Employees.frxReport.DataSets.Clear;
    Employees.frxReport.DataSets.Add(frxDBDataset1);
    Employees.frxReport.DataSets.Add(frxDBDataset2);
    Employees.frxReport.DataSets.Add(frxDBDataset3);

    // DESIGN MODE
      //Employees.frxReport.LoadFromFile(ExtractFilePath(Application.ExeName)+'Report\Cards.fr3');
      //Employees.frxReport.DesignReport;

    // PREVIEW MODE
      frxDBDataset1.DataSet.Close;
      frxDBDataset2.DataSet.Close;
      frxDBDataset3.DataSet.Close;

      Employees.frxReport.LoadFromFile(ExtractFilePath(Application.ExeName)+'Report\Cards.fr3');
      Employees.frxReport.ShowReport;

    frxDBDataset1.Free;
    frxDBDataset2.Free;
    frxDBDataset3.Free;

end;

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

Не совсем понятна разница между DESIGN MODE и PREVIEW MODE, хотелось бы узнать подробнее об этом.

Шаг 3. Возможность выбора шаблона отчета у кнопки с действием "Отчет":

Form1.ButtonReport.dbReportFile:='print.fr3'; 

Вообще шикарный инструмент. Must to use.

Шаг 4. Составной отчет. В котором несколько блоков ReportTitle, MasterData, Footer. Возможность создания - через метод TfrxReport.PrepareReport и скрипт а-ля

frxReport1.LoadFromFile('1.fr3');
frxReport1.PrepareReport;
frxReport1.LoadFromFile('2.fr3');
frxReport1.PrepareReport(False);
frxReport1.ShowPreparedReport;

Данная возможность расписана слабо, и хотелось бы узнать о ней побольше.

Re: Создание сложного отчета - алгоритм решения проблемы.

Не совсем понятна разница между DESIGN MODE и PREVIEW MODE, хотелось бы узнать подробнее об этом.


DESIGN MODE - необходим для редактирования шаблона отчета, т.е. при нажатии на кнопку вы увидите не отчет, а дизайнер отчета с загруженными данными из БД.


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



Шаг 4. Составной отчет. 
Данная возможность расписана слабо, и хотелось бы узнать о ней побольше.

Скачайте пожалуйста последнюю бета версию
https://www.dropbox.com/s/wutj7mnux7f3a … a.zip?dl=0


Сделал проект с примером

Post's attachments

Attachment icon Report merge reports.zip 11.43 kb, 518 downloads since 2018-07-16 

Dmitry.

3 (edited by m.prokhachev 2018-07-16 14:06:58)

Re: Создание сложного отчета - алгоритм решения проблемы.

То есть сам MVD, по сути, это расширение FastReport'а до некой заточенной под создание СУБД IDE, ясно)

Ага, посмотрел код, понял, куда лепить куски из шага 4. Получается, мы тупо соединяем два шаблона в один генеральный шаблон. И можно не заморачиваться с наследуемыми отчетами.

4 (edited by m.prokhachev 2018-07-16 14:33:01)

Re: Создание сложного отчета - алгоритм решения проблемы.

Тогда вопрос такой: из кучи малосвязанных и несвязанных таблиц возможно ли подготовка и наполнение такого вот установочного отчета (см. по ссылке)???

Сейчас это делают вручную, но таких отчетов до хрена, и это нужно автоматизировать. Мало меняются данные о составе комиссии (но тем не менее, изредка меняются), в основном меняется номер акта, дата и данные в таблице 1. То, что выводится из БД - помечено желтым (даже тип организации члена комиссии). БД под все это уже сделана (см. по ссылке). Осталось написать алгоритмы.

https://ru.files.fm/u/ug2wnfct

Re: Создание сложного отчета - алгоритм решения проблемы.

Да, это вполне возможно, отчет не выглядит сложным.

Dmitry.

Re: Создание сложного отчета - алгоритм решения проблемы.

Далее нюансы пошли:

Нюанс 1. Передача переменных в отчет, не связанных с БД.
1) можно добавлять компоненты в отчет, даже если они не связаны с БД, таким образом их значение будет передано в отчет и не будут учавствовать в поиске. При этом компоненты формы должны быть в списке "Участвующие в поиске" при настройке кнопки с действием "Отчет".
2) можно добавлять переменные в отчет с помощью скрипта, для этого создайте событие OnClick для кнопки с действием "Отчет"

procedure Form1_ButtonReport_OnClick (Sender: TObject; var Cancel: boolean);
begin
    Form1.frxReport.Variables.Clear;
    Form1.frxReport.Variables[' ' + 'My Category 1'] := Null;
    Form1.frxReport.Variables['My Variable 1'] := 10;
    Form1.frxReport.Variables['My Variable 2'] := 20;
    Form1.frxReport.Variables['My Variable 3'] := '''Hello''';
end;

Здесь не очень понятна строка Form1.frxReport.Variables[' ' + 'My Category 1'] := Null; - это типа название переменной с пробелом перед названием? а зачем?

Re: Создание сложного отчета - алгоритм решения проблемы.

1. Все верно.


Здесь не очень понятна строка Form1.frxReport.Variables[' ' + 'My Category 1'] := Null; - это типа название переменной с пробелом перед названием? а зачем?

Таким образом создается своя категория переменных. В списке переменных, ваши переменные будут размещены с разделе с названием "My Category 1", само собой имя категории можно задать любое.

Dmitry.

Re: Создание сложного отчета - алгоритм решения проблемы.

а Form1.frxReport.Variables.Clear; очистит и те переменные, которые придут через грид?

Re: Создание сложного отчета - алгоритм решения проблемы.

m.prokhachev wrote:

а Form1.frxReport.Variables.Clear; очистит и те переменные, которые придут через грид?

К сожалению не ясно, что такое переменные, которые придут через грид.
В любом случае, просто попробуйте )

Dmitry.

10 (edited by m.prokhachev 2018-07-23 14:47:46)

Re: Создание сложного отчета - алгоритм решения проблемы.

ну c имеющегося TableGrid мы формируем DataSet такой же структуры, а потом уже впихиваем это в DBDataSet.. как я понимаю этот процесс... могу и неверно себе это представлять... Отсюда и вопрос - очистка Variables затронет DataSet'ы?

Сразу же и второй вопрос: как текущее содержимое TableGrid на форме присвоить переменной типа TDataSet?

Re: Создание сложного отчета - алгоритм решения проблемы.

Пошли первые проблемы... На кусок кода:

frmSettingReport.frxReport.Variables.Clear;
frmSettingReport.frxReport.Variables[' ' + 'UserVariables'] := Null;
frmSettingReport.frxReport.Variables['ReportCode'] := 'М' + GroupID + '-00' + FormatDateTime('yy', now); // формируем шифр отчета

MVD ругается "Undeclared identifier". Где и что надо прописать?..

Re: Создание сложного отчета - алгоритм решения проблемы.

В сообщении об ошибке должно быть написано, что именно является Undeclared identifier


вместо название формы frmSettingReport, необходимо использовать название главной формы проекта.

Dmitry.

Re: Создание сложного отчета - алгоритм решения проблемы.

Ругается именно на frxReport. Ок, принято - указывать главную форму проекта. Компонент на ней висит, значит.

А по поводу присвоения содержимого TableGrid переменной типа TDataSet что скажете?

Re: Создание сложного отчета - алгоритм решения проблемы.

m.prokhachev wrote:

А по поводу присвоения содержимого TableGrid переменной типа TDataSet что скажете?

напрямую нет возможности это сделать, но в принципе есть возможность получить SQL запрос, который был использован для заполнения TableGrid

Form1.TableGrid1.dbGetSqlStatement

затем использовать этот SQL запрос для формирования DataSet в функции SQLQuery


К сожалению не совсем ясно, зачем так делать, какая задача стоит пред вами?

Dmitry.

Re: Создание сложного отчета - алгоритм решения проблемы.

Задача стоит такая: выбрать в гриде мультиселектом (например, по методу derek'а) несколько позиций-строк и передать их в отчет через DataSet.
Тогда вопрос стоит так: любое изменение наполнения грида имеет актуальное на текущий момент TableGrid1.dbGetSqlStatement?
Например, при показе формы грид заполняется по настройкам в самом гриде, в процессе работы с формой содержимое грида меняется (например, изменяется количество показанных строк) при помощи кнопок поиска-фильтрации, а при этом TableGrid1.dbGetSqlStatement меняет свое значение-содержимое?

Re: Создание сложного отчета - алгоритм решения проблемы.

m.prokhachev wrote:

Задача стоит такая: выбрать в гриде мультиселектом (например, по методу derek'а) несколько позиций-строк и передать их в отчет через DataSet.

Можно сформировать SQL запрос, в котором условие WHERE будет формироваться динамически скриптом, где в цикле будет проверяться, выделена ли запись в гриде
пример

     sSQL := 'SELECT lastname, firstname, id FROM employees WHERE ';

     c := Form1.TableGrid1.RowCount - 1; // count of records in TableGrid
     for i :=0 to c do
         if Form1.TableGrid1.Selected[i] then // if record selected
            sSQL := sSQL + 'id = ' + IntToStr(Form1.TableGrid1.dbIndexToID(i)) + ' OR ';

     SetLength(sSQL, Length(sSQL)-4); // ' OR ' deleted at the end

m.prokhachev wrote:

Тогда вопрос стоит так: любое изменение наполнения грида имеет актуальное на текущий момент TableGrid1.dbGetSqlStatement?
Например, при показе формы грид заполняется по настройкам в самом гриде, в процессе работы с формой содержимое грида меняется (например, изменяется количество показанных строк) при помощи кнопок поиска-фильтрации, а при этом TableGrid1.dbGetSqlStatement меняет свое значение-содержимое?

Да, свойство dbGetSqlStatement имеет актуальный SQL запрос

Dmitry.

Re: Создание сложного отчета - алгоритм решения проблемы.

Ок, а возможен гибридный вариант сборки данных в отчет: часть данных придет с грида на активной форме, часть данных соберется при помощи скрипта на событии OnClick кнопки с действием "отчет" на этой же форме?

Re: Создание сложного отчета - алгоритм решения проблемы.

И сразу еще вопрос по пониманию сути вещей...
В этом примере

frxDBDataset1 := TfrxDBDataset.Create(Employees);
frxDBDataset1.UserName        := 'Employee';
frxDBDataset1.CloseDataSource := True;
frxDBDataset1.OpenDataSource  := True;
frxDBDataset1.DataSet         := Employee;

какой параметр за что отвечает?
Потому как мой кусок кода:

frxDBDataset_Sensors := TfrxDBDataset.Create(SensorsSettingData);
frxDBDataset_Sensors.UserName        := 'SensorsSettingData';
frxDBDataset_Sensors.CloseDataSource := True;
frxDBDataset_Sensors.OpenDataSource  := True;
frxDBDataset_Sensors.DataSet         := SensorsSettingData;

SensorsSettingData.frxReport.Clear;
SensorsSettingData.frxReport.DataSets.Clear;
SensorsSettingData.frxReport.DataSets.Add(frxDBDataset_Sensors);

опять не нравится интерпретатору-компилятору с сообщением "Undeclared identifier: frxReport"... Опять что-то с главной формой связано?

Re: Создание сложного отчета - алгоритм решения проблемы.

frxDBDataset1 := TfrxDBDataset.Create(Employees); // создание объекта
frxDBDataset1.UserName        := 'Employee'; // задаем имя датасета для отчета
frxDBDataset1.CloseDataSource := True; // не знаю
frxDBDataset1.OpenDataSource  := True; // не знаю
frxDBDataset1.DataSet         := Employee; // присваиваем датасет данному объекту

опять не нравится интерпретатору-компилятору с сообщением "Undeclared identifier: frxReport"

SensorsSettingData является главной формой? больше похоже что это DataSet
Возможно вы используете одно и тоже имя как для формы так и для DataSet-а, не видя проекта к сожалению не могу сказать точно.

Dmitry.

20 (edited by m.prokhachev 2018-07-25 16:13:43)

Re: Создание сложного отчета - алгоритм решения проблемы.

Дело в том, что по данному куску кода кажется, что объект именуется как Emploees с s на конце, а присваиваем датасет с именем Emploee (без s). Получается Emploees - это имя формы, к которой привязывается frxDBDataset? Или это опечатка? Потому что в примере такой переменной Emploees (с s на конце) не имеется.

SensorsSettingData не является главной формой, в том-то всё и дело. Это имя переменной типа TDataSet. Я отчет создаю при помощи второстепенной формы. Получается, я неверно понял пример кода. Значит, надо использовать так же имя главной формы в этом куске кода:

frmMain.frxReport.Clear;
frmMain.frxReport.DataSets.Clear;
frmMain.frxReport.DataSets.Add(frxDBDataset_Sensors);

21 (edited by m.prokhachev 2018-07-25 16:30:09)

Re: Создание сложного отчета - алгоритм решения проблемы.

Так, ладно, заработало. Пока что.
Однако после выполнения куска кода

frmMain.frxReport.Variables.Clear;
frmMain.frxReport.Variables[' ' + 'UserVariables'] := Null;

frmMain.frxReport.Variables['ReportCode'] := 'М' + GroupID + '-00' + FormatDateTime('yy', now); // формируем шифр отчета

почему-то в разделе Variables в дизайнере отчета не появляется ни указанная переменная с именем ReportCode, ни категория переменных с именем UserVariables. Что здесь я не так делаю?

Re: Создание сложного отчета - алгоритм решения проблемы.

Попробуйте так

frmMain.frxReport.Variables['ReportCode'] := '''М' + GroupID + '-00' + FormatDateTime('yy', now)+''''; // формируем шифр отчета

Если не заработает, приложите пожалуйста ваш проект

Dmitry.

23 (edited by m.prokhachev 2018-07-26 09:58:04)

Re: Создание сложного отчета - алгоритм решения проблемы.

Дмитрий, держите - https://drive.google.com/open?id=1PA6Hv … 0-xjbUXAtL, не работает

Re: Создание сложного отчета - алгоритм решения проблемы.

Переменные должны устанавливаться здесь

  // DESIGN MODE
  frmMain.frxReport.LoadFromFile(ExtractFilePath(Application.ExeName)+'Report\SR.fr3');
  frmMain.frxReport.Variables.Clear;
  frmMain.frxReport.Variables[' ' + 'UserVariables'] := Null;
  frmMain.frxReport.Variables['ReportCode'] := ''+'М' + GroupID + '-00' + FormatDateTime('yy', now) + ''+''; // формируем шифр отчета
  frmMain.frxReport.DesignReport;

  // PREVIEW MODE
  //frxDBDataset_Sensors.DataSet.Close;
  //frmMain.frxReport.LoadFromFile(ExtractFilePath(Application.ExeName)+'Report\SR.fr3');
  //frmMain.frxReport.Variables.Clear;
  //frmMain.frxReport.Variables[' ' + 'UserVariables'] := Null;
  //frmMain.frxReport.Variables['ReportCode'] := ''+'М' + GroupID + '-00' + FormatDateTime('yy', now) + ''+''; // формируем шифр отчета
  //frmMain.frxReport.ShowReport;

Иначе они очищаются после вызова frmMain.frxReport.Clear;

Dmitry.

25 (edited by m.prokhachev 2018-07-27 11:39:54)

Re: Создание сложного отчета - алгоритм решения проблемы.

О как! спасибо большое! сам че-то не додумался...

И последний тогда вопрос:
этот код использовать только при PREVIEW MODE?

frxDBDataset_Sensors.Free;
frxDBDataset_Committee.Free;