Стараюсь писать про Аксапту, хотя частенько тянет в Офис
Построение сводной таблицы на форме с загрузкой данных из ADODB.Recordset
Запись от Gustav размещена 17.05.2010 в 19:00
Сразу определимся с терминами. "Сводная таблица на форме" - это Office Web Component PivotTable, размещенный как элемент управления ActiveX на форме Аксапты. "ADODB.Recordset" - в первую (и наиболее интересную для нас) очередь отсоединенный (или неприсоединенный, или, если угодно, disconnected), в общем, не связанный с базой данных набор записей, формируемый программистом в оперативной памяти (процесс во многом напоминает заполнение массива: Вывод в Excel через Array). Работа с отсоединенным ADODB.Recordset подробно описана в теме Поговорим об ADO, а также в ряде других смежных обсуждений (Строка в Excel, экспорт в шаблон excel и т.п.).
До недавнего времени я не знал о существовании возможности подачи данных в OWC PivotTable из отсоединенного Recordset'а, будучи, тем не менее, в курсе подобной возможности для сводной таблицы в Excel через PivoteCache (Вывод в Excel сводной таблицы "пользователи-группы"). В том своем сообщении я очень сожалел об отсутствии объекта PivotCache у OWC PivotTable. И думал, что данные могут поступать только из Recordset'ов, связанных с реальными таблицами БД.
Оказалась, что возможность загрузки из неприсоединенного Recordset'а всё-таки существует! Не в том смысле, что нашёлся PivotCache у PivotTable - его как не было, так и нет - и это на сегодняшний день медицинский факт. Но в том смысле, что загружать данные всё-таки можно, хотя и несколько идеологически иначе - при помощи метода PivotTable.DataSource( recordset ): см. Сводные таблицы и Olap в Dax2009.
Приводимый ниже джоб - мой первый опыт работы с OWC PivoteTable на форме. Поэтому можно говорить о том, что публикую я его больше как узелок на память для самого себя, нежели как "лекцию" по пивотостроению (хм, и здесь пиво... ).
Джоб решает по сути абсолютно ту же задачу, что и джоб из сообщения Вывод в Excel сводной таблицы "пользователи-группы". Поэтому оба листинга полезно сравнить буквально пооператорно, определяя моменты сходства и отличия между "большим" Excel и "маленьким" OWC. Очень интересен в этом отношении способ гашения итогов: при визуальной схожести фрагментов "Subtotals(1, false)" они обнаружили заметное различие по смыслу. В Excel первый параметр - одно из значений перечисления: 1-Automatic, 2-Sum, 3-Count,..., 11-Var,12-Varp. В OWC PivotTable - "Must be 1" (см.комментарий и ссылку в коде).
При подготовке этого сообщения я использовал следующие материалы для изучения вопроса и написания джоба:
До недавнего времени я не знал о существовании возможности подачи данных в OWC PivotTable из отсоединенного Recordset'а, будучи, тем не менее, в курсе подобной возможности для сводной таблицы в Excel через PivoteCache (Вывод в Excel сводной таблицы "пользователи-группы"). В том своем сообщении я очень сожалел об отсутствии объекта PivotCache у OWC PivotTable. И думал, что данные могут поступать только из Recordset'ов, связанных с реальными таблицами БД.
Оказалась, что возможность загрузки из неприсоединенного Recordset'а всё-таки существует! Не в том смысле, что нашёлся PivotCache у PivotTable - его как не было, так и нет - и это на сегодняшний день медицинский факт. Но в том смысле, что загружать данные всё-таки можно, хотя и несколько идеологически иначе - при помощи метода PivotTable.DataSource( recordset ): см. Сводные таблицы и Olap в Dax2009.
Приводимый ниже джоб - мой первый опыт работы с OWC PivoteTable на форме. Поэтому можно говорить о том, что публикую я его больше как узелок на память для самого себя, нежели как "лекцию" по пивотостроению (хм, и здесь пиво... ).
Джоб решает по сути абсолютно ту же задачу, что и джоб из сообщения Вывод в Excel сводной таблицы "пользователи-группы". Поэтому оба листинга полезно сравнить буквально пооператорно, определяя моменты сходства и отличия между "большим" Excel и "маленьким" OWC. Очень интересен в этом отношении способ гашения итогов: при визуальной схожести фрагментов "Subtotals(1, false)" они обнаружили заметное различие по смыслу. В Excel первый параметр - одно из значений перечисления: 1-Automatic, 2-Sum, 3-Count,..., 11-Var,12-Varp. В OWC PivotTable - "Must be 1" (см.комментарий и ссылку в коде).
X++:
#CCADO static void Job_showUserGroupInActiveXPivot(Args _args) { Form form = new Form(); FormBuildDesign formBuildDesign = form.addDesign('Design'); Args args = new Args(); FormRun formRun; FormActiveXControl pivotTable; UserGroupList userGroupList; UserInfo userInfo; UserGroupInfo userGroupInfo; COM rst,flds,fld; // переменные ADO COM ptConstants; // переменные PivotTable COM activeView; COM avFieldSets, fieldSet; COM pivotFields, pivotField, pivotTotal; COM comTemp; void processFieldSet(COM _axis, str _fieldSetName) { fieldSet = avFieldSets.Item(_fieldSetName); _axis.InsertFieldSet(fieldSet); // добавляем FieldSet в ось (т.е в Строки или в Столбцы) pivotFields = fieldSet.Fields(); // в семействе полей FieldSet'а... pivotField = pivotFields.Item(0); // ...находим единственное поле... (индексация начинается с 0) pivotField.Subtotals(1, false); // ...и гасим (false) для него промежуточные итоги // по поводу 1 см. "Must be 1" в [url]http://msdn.microsoft.com/en-us/library/aa831714(office.10).aspx[/url] } ; // готовим рекордсет rst = AdoRst::openRecordsetInMemory([ // метод можно взять здесь: [url]http://www.axforum.info/forums/blog.php?b=60[/url] ['UserId' , #adVarChar, 5 ], ['UserName' , #adVarChar, 40 ], ['GroupId' , #adVarChar, 10 ], ['GroupName' , #adVarChar, 40]]); flds = rst.Fields(); while select userGroupList join userInfo where userInfo.id == userGroupList.userId join userGroupInfo where userGroupInfo.id == userGroupList.groupId { rst.AddNew(); fld = flds.Item('UserId' ); fld.Value(userGroupList.userId ); fld = flds.Item('UserName' ); fld.Value(userInfo.name ); fld = flds.Item('GroupId' ); fld.Value(userGroupList.groupId); fld = flds.Item('GroupName'); fld.Value(userGroupInfo.name ); rst.Update(); } // динамически генерируем форму args.object(form); formRun = classFactory.formRunClass(args); formRun.init(); formRun.design().caption('Сводная таблица "Пользователи-Группы"'); pivotTable = formRun.design().addControl(FormControlType::ActiveX, 'PivotTable'); pivotTable.className('{0002E542-0000-0000-C000-000000000046}'); // Microsoft Office PivotTable 10.0 pivotTable.heightMode(FormHeight::ColumnHeight); // именно heightMode ! не путать с просто height pivotTable.widthMode(FormWidth::ColumnWidth); // именно widthMode ! не путать с просто width pivotTable.AutoFit(false); ptConstants = pivotTable.Constants(); // для использования ниже именованной константы plFunctionCount // передаем рекордсет ActiveX'у pivotTable.DataSource(rst); activeView = pivotTable.ActiveView(); avFieldSets = activeView.FieldSets(); // список доступных полей рекордсета для размещения в сводной таблице // сокрытие разных "визуальных раздражителей" (здесь хорошо помог \Classes\GM_PivotViewManager\ initDefaultViewProperties от GMCS) COM::createFromObject( pivotTable.ActiveData() ).HideDetails(); // это лучше сделать до размещения полей и особенно итогов - иначе летаргически долго COM::createFromObject( activeView.TitleBar() ).Visible(false); // выключение синего заголовка "Сводная таблица MS Office 10.0" comTemp = ActiveView.FilterAxis(); COM::createFromObject( comTemp.Label() ).Visible(false); // выключение области "Перетащите сюда поля фильтра" pivotTable.AllowDetails(false); // чтобы убрались "+/-" и не получать надпись "Нет деталей" pivotTable.DisplayOfficeLogo(false); // выключение самой левой красно-сине-желто-зеленой кнопки на панели // наполняем строки полями UserName и UserId processFieldSet(activeView.RowAxis(), 'UserName'); processFieldSet(activeView.RowAxis(), 'UserId'); // наполняем столбцы полями GroupId и GroupName processFieldSet(activeView.ColumnAxis(), 'GroupId'); processFieldSet(activeView.ColumnAxis(), 'GroupName'); // наполняем область данных итогом - подсчетом кол-ва по полю GroupName (это поле осталось в переменной pivotField после его вставки в столбцы) pivotTotal = activeView.AddTotal('Количество', pivotField, ptConstants.plFunctionCount()); // использование именованной константы COM::createFromObject( activeView.DataAxis() ).InsertTotal(pivotTotal); formRun.run(); formRun.wait(); }
- файл помощи OWCVBA10.CHM на своем компьютере, а также другие источники, описанные в сообщении Сводные таблицы и Olap в Dax2009;
- демонстрационный пример Ivanhoe из сообщения Сводные таблицы и Olap в Dax2009;
- наработки компании GMCS, которые нашёл в AOT нашей корпоративной Аксапты (3.0, SP4) - классы и формы с именами, начинающимися на "GM_Pivot"; пример работающей реализации этого хозяйства можно увидеть (клиентам GMCS!) по маршруту: Управление запасами \Запросы \Оборотно-сальдовая ведомость по складу \вкладка Обзор \кнопка Сводная таблица);
- Метод \Classes\SysTableLookup\formRun - для подсматривания простейшего способа создания динамической формы без использования класса Dialog.
Всего комментариев 1
Комментарии
-
Мне кажется метод не коректно отрабатывает, хотя я могу ошибаться.
Когда вы сделали сводную таблицу и нажимаете на кнопку "экспорт в эксель" у вас происходит выгрузка? у меня вылезает ошибка
DAX 2009
Я потратил много времени, чтобы выяснить что именно не так.
Надо добавить строку
X++:#define.adAffectAll(3) ... rst.UpdateBatch(#adAffectAll);
Запись от refined размещена 31.03.2011 в 16:11
Обновил(-а) refined 31.03.2011 в 18:25