На проектах внедрения отчетности с использованием хранилища данных SAP BW многим архитекторам и консультантам приходится решать задачи подготовки больших форматированных отчетов: разнообразных ведомостей, выписок и т.п. Такие отчеты обычно характеризуются:
- Нестандартными относительно инструментов SAP требованиями к форматированию;
- Фиксированным числом столбцов;
- Значительным количеством столбцов и строк (соответственно, десятки и десятки тысяч и более);
- Требованием наличия Excel-представления;
- Требованием к времени выполнения не более нескольких минут
К сожалению, нередко приходится наблюдать ситуацию, когда архитекторы BW-проектов выбирают стандартный для BW подход реализации таких отчетов. Кратко суть этого подхода изложена ниже.
Консультантом создается рабочая книга BW-BEx, которая содержит один или несколько BW-BEx-отчетов. Отчеты выгружаются на отдельные листы этой книги, которые обычно скрывают от пользователей. Видимым оставляют лишь один лист книги, содержащий целевую форму отчета с необходимым форматированием.
Работа пользователя с таким отчетом выглядит следующим образом:
- в зависимости от используемого Excel-инструмента SAP BW, пользователь запускает BW-BEx Analyzer или SBOP Analysis for Office, подключается к серверу SAP BW, выбирает из роли рабочую книгу и запускает ее на выполнение.
Через несколько секунд (иногда – десятка секунд) появляется селекционный экран.
На экране пользователь выбирает значения параметров. Например, год-месяц, балансовую единицу, группу материала и т.п. Затем нажимает кнопку «выполнить». - Теперь настала очередь «поработать» для SAP BW: все BW-BEx-отчеты рабочей книги выполняются последовательно, отчет за отчетом, передавая на рабочие листы Excel свои данные.
- После получения в Excel данных каждого отчета запускается VBA-макрос. Логика работы макроса такова, что он ничего не делает, пока данные всех отчетов не будут получены на Excel-листы.
- Когда данные последнего отчета поступили на Excel-лист, VBA-макрос выполняет основную работу по подготовке форматирования отчета.
- Когда VBA-макрос завершил работу, пользователь может увидеть результат отчета в своем Excel.
У стандартного подхода есть ряд преимуществ: он прост в реализации и им хорошо владеют большинство специалистов на рынке. Но определенные ограничения не позволяют эффективно реализовывать большие отчеты. А неэффективная реализация получается (если вообще получается) очень неудобной в работе, что негативно сказывается на отношении пользователей к проекту внедрения вообще и к SAP BW в частности. Основное ограничение – максимальное количество ячеек (число строк, умноженное на число столбцов) в отчете. Если их число приближается к эмпирическим 750000, то вероятность сбоя из-за нехватки памяти практически 100%. Т.е. отчет из всего 18 колонок и чуть более 40000 строк уже попадает под это ограничение. А ведь лимиты у Excel намного больше.
Чего только не придумывают консультанты, чтобы, оставаясь в рамках стандартного подхода, качественно сделать-таки большой отчет. Но почти всегда ничего не получается. «Почти» означает компромиссы, послабления в требованиях. Бизнес-пользователи либо соглашаются применять более ограничивающие фильтры и отчет возвращает меньше данных, либо ждать выполнения подольше, либо вручную сводить несколько фрагментов отчета в один.
Чтобы все-таки не говорить клиенту «нет, мы не можем этого реализовать при таких требованиях», необходимо для начала сделать правильные выводы из очевидного: каждый инструмент предназначен для своей задачи.
Инструменты BW BEx Analyzer и SBOP Analysis for Office в общем случае не предназначены для реализации эффективных отчетов с большим количеством ячеек, с числом около 750000 и более (см SAP-ноту 1040454). Поэтому, используя модель данных SAP BW, надо выбрать другой инструмент, другой подход в реализации. Тогда решение не только обязательно получится, но и будет при этом эффективным.
Последние версии SAP Netweaver, SAP BW и HANA внесли большее разнообразие подходов публикации BW-данных в Excel, без использования BW BEx. Можно упомянуть такие:
- Подключение Excel через OData-сервисы напрямую к SAP Netweaver или даже к SAP HANA
- Подключение Excel к SAP HANA, как к базе данных, напрямую, через MDX
Однако, эти подходы требуют либо BW on HANA, либо новейших версий Excel, либо отклонений от привычных концепций полномочий, при которой пользователи не работают с приложениями, обращающимися напрямую к БД.
Я хочу рассказать о подходе, гораздо менее требовательном к новизне версий используемых продуктов, и в чем-то менее сложным. Речь идет о публикации данных отчетов в шаблон Excel-документа через OLE-интерфейс. Excel-шаблон при этом хранится в репозитории BDS на стороне SAP BW.
Преимущества подхода с OLE очевидны:
- Работает на любых современных версиях продуктов SAP и Microsoft Excel
- Никаких ограничений на объемы данных в отчете, кроме собственных в Excel
- Обеспечивает максимальную производительность передачи данных от сервера BW в Excel через OLE. Пример: выборка 525000 ячеек (70 колонок на 7500 строк) передается за 7 сек.
- Подготовка данных на «сервере BW» выполняется в ABAP-отчете, который, собрав выборку во внутреннюю таблицу, передает ее через OLE в Excel-шаблон, полученный из BDS.
- Централизованное (в одной BW-системе) ведение всех объектов, релевантных для отчета: шаблон Excel, модель данных BW, программа ABAP для заполнения шаблона.
- Соответствие обычным SAP-стандартам по разграничению доступа, разработке, транспорту настроек и пр.
«Обратная сторона» медали – этот подход требует программирования на ABAP. Но, по мнению автора, этот аспект не должен вызывать существенных трудностей. «Обертка» из вызова Excel-файла из BDS, его заполнения данными и сохранения, например, в файл на диске или обратно в BDS — более менее стандартный код, который с минимальными вариациями используется от отчета к отчету.
Сложности в ABAP могут возникнуть при получении данных из модели BW. Возможные варианты: вызов BEx-отчета в ABAP, вызов FM RSDRI_INFOPROV_READ, SQL-SELECT по таблицам модели данных. Но это обычно есть в арсенале навыков опытного BW-консультанта. Глубокие знания программировании ABAP понадобятся, если возникнет потребность еще более ускорить работу кода по подготовке данных за счет тюнинга ABAP-программы или даже распараллеливания вычислений. Последнее, кстати, невозможно архитектурно в подходе с рабочими книгами BW BEx.
Вкратце, порядок создания отчета с использованием подхода с OLE следующий.
- Разработка и отладка кода ABAP, который возвращает во внутреннюю таблицу данных отчета в соответствии с входными параметрами. ABAP-код может быть в виде FM, а лучше – в виде статического метода ABAP-класса;
- Подготовка Excel-шаблона отчета с базовым форматированием и vBA-макросом, который выполняется после заполнения данными. Такой макрос обычно принимает параметр «число строк», хотя и это не обязательно. Задачи макроса – применить форматирование ячеек отчета при условии неизвестного наперед количества строк;
- Помещение Excel-шаблона в репозиторий BDS;
- Разработка и отладка ABAP-кода, который заполняет внутреннюю таблицу результатов отчета, считывает из BDS Excel-шаблон, помещает в него данные из внутренней таблицы в соответствии с мэппингом «поле в таблице – поле в шаблоне», запускает на выполнение VBA-макрос, сохраняет заполненный файл на диске во временном каталоге и открывает его на просмотр пользователю;
- Подготовка пользовательской транзакции, которая готовится на основе разработки из предыдущего пункта.
Что может понадобится, чтобы сделать первый пример на основе подхода с ABAP-OLE и успешно применять его в дальнейшем?
- Транзакция работы с репозиторием BDS: OAOR
- Фрагменты ABAP-кода по работе с документами из BDS (см ниже)
- Фрагменты ABAP-кода по работе с Excel через OLE (см. ниже)
- Сертификат для макроса VBA или разрешающая опция Excel по запуску макросов (см. support.microsoft.com/en-us/kb/206637)
data: l_iref_template type ref to cl_bds_document_set, l_oref_container type ref to cl_gui_custom_container, l_iref_control type ref to i_oi_container_control, l_iref_error type ref to i_oi_error, l_iref_document type ref to i_oi_document_proxy, l_iref_spreadsheet type ref to i_oi_spreadsheet, l_retcode type soi_ret_string. data: lt_signature type sbdst_signature, lw_signature type bapisignat, lt_uri type sbdst_uri, lw_uri type bapiuri, lt_sheet type soi_sheets_table, lw_sheet type soi_sheets. data: lt_fields type standard table of rfc_fields, lv_last_row type i, lv_last_col type i. call method c_oi_container_control_creator=>get_container_control importing control = l_iref_control retcode = l_retcode. check l_retcode = c_oi_errors=>ret_ok. call method l_iref_control->init_control exporting r3_application_name = pv_template inplace_enabled = 'X' inplace_scroll_documents = 'X' parent = l_oref_container importing retcode = l_retcode. check l_retcode = c_oi_errors=>ret_ok. create object l_iref_template. lw_signature-prop_name = 'DESCRIPTION'. lw_signature-prop_value = pv_template. append lw_signature to lt_signature. refresh lt_uri. call method l_iref_template->get_with_url exporting classname = 'SOFFICEINTEGRATION' classtype = 'OT' object_key = 'SOFFICEINTEGRATION' changing uris = lt_uri signature = lt_signature exceptions nothing_found = 1 error_kpro = 2 internal_error = 3 parameter_error = 4 not_authorized = 5 not_allowed = 6. clear lw_uri. read table lt_uri into lw_uri index 1. check sy-subrc = 0. call method l_iref_control->get_document_proxy exporting document_type = 'Excel.Sheet' importing document_proxy = l_iref_document retcode = l_retcode. check l_retcode = c_oi_errors=>ret_ok. call method l_iref_document->open_document exporting document_url = lw_uri-uri open_inplace = 'X' importing retcode = l_retcode. check l_retcode = c_oi_errors=>ret_ok. free l_iref_error. call method l_iref_document->get_spreadsheet_interface importing error = l_iref_error sheet_interface = l_iref_spreadsheet. call method l_iref_spreadsheet->get_sheets importing sheets = lt_sheet error = l_iref_error. check l_iref_error->error_code = c_oi_errors=>ret_ok. clear lw_sheet. read table lt_sheet into lw_sheet index 1. check sy-subrc = 0. call method l_iref_spreadsheet->select_sheet exporting name = lw_sheet-sheet_name importing error = l_iref_error. check l_iref_error->error_code = c_oi_errors=>ret_ok. refresh lt_fields. call function 'DP_GET_FIELDS_FROM_TABLE' tables data = pt_excel fields = lt_fields. lv_last_row = lines( pt_excel ). lv_last_col = lines( lt_fields ). call method l_iref_spreadsheet->set_selection exporting left = 1 top = 2 rows = lv_last_row columns = lv_last_col. call method l_iref_spreadsheet->insert_range exporting columns = lv_last_col rows = lv_last_row name = pv_template. call method l_iref_spreadsheet->insert_one_table exporting data_table = pt_excel[] fields_table = lt_fields rangename = pv_template. … call method l_iref_document->execute_macro exporting macro_string = 'Module1.MakeFormat' * no_flush = ' ' param1 = 10 param_count = 1 importing error = l_iref_error retcode = l_retcode … concatenate pv_file sy-uzeit '.xls' into pv_file. call method l_iref_document->save_as exporting file_name = pv_file. call method l_iref_document->release_document importing retcode = l_retcode. free: l_iref_spreadsheet, l_iref_document. call method l_iref_control->release_all_documents. call method l_iref_control->destroy_control. create object lo_application 'Excel.Application'. if sy-subrc <> 0. write: / 'Create application: RETURN CODE ='(I10), sy-subrc. exit. endif. call method of lo_application 'Workbooks' = lo_workbooks. if sy-subrc <> 0. write: / 'Application->Workbooks: RETURN CODE ='(I10), sy-subrc. exit. endif. call method of lo_workbooks 'Open' = lo_workbook exporting #1 = lv_filename. if sy-subrc <> 0. write: / 'Workpook->Open: RETURN CODE ='(I10), sy-subrc. exit. endif. set property of lo_application 'Visible' = 1. call method of lo_application 'Run' exporting #1 = 'Module1.MakeFormat' #2 = lv_last_row. if sy-subrc <> 0. write: / 'Macro run: RETURN CODE ='(I10), sy-subrc. exit. endif.
ссылка на оригинал статьи http://habrahabr.ru/post/269675/
Добавить комментарий