Ещё по теме

Комментарии по теме

«Будущее SAP»
Артем Седловский:
Добрый день всем! Интересная философская статья. Позволю себе ответить на вопросы, заданные в конце. К сожалению, в развитии продуктов и особенно в приобретениях лично я наблюдаю отсутствие...
«Битва титанов. Часть 1. Краткая история большой тройки (Не­за­ви­си­мое сравнение SAP, Oracle и Microsoft Dynamics)»
Олег Точенюк:
Эх, да бы не быть обвиненным в плагиате :-), но уже года как полтора назад было вложено: мной:   ---------------------- Тут типа бойцы из Panorama Consulting Group решили сравнить две...
«Проблемы инте­гра­ции SAP ERP и внешнего ЭДО. Мы их решили!»
Ирина Хатилович:
Спасибо! По этой теме есть интересная статья от Александра Болгарина (ссылка: sapland.ru/events/sammit-po-lokalizatsii-reshenii-sap-2014 ). На нашем предприятии уже применяется. Но, в любом...

База знаний

Консоль запросов для SAP ERP. Выполнение SQL-запросов

4169
19

Системный ландшафт и процесс разработки ABAP-программ

При внедрении информационно-управляющей системы на базе SAP ERP, как правило, разворачивается комплекс систем:

  1. Система разработки.
  2. Система тестирования.
  3. Система продуктивной эксплуатации.

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

Стандартная ситуация: программист пишет код в системе разработки, переносит его в тестовую систему и в процессе тестирования обнаруживает, что написанный код работает некорректно, после чего он возвращается в систему разработки для исправления ошибок, а затем повторно переносится в тестовую систему (Рис. 1). Этот процесс зацикливается, и каждая такая итерация отнимает около десяти «непродуктивных» минут, которые разработчик тратит на рутинные действия по переносу запроса. И таких итераций может потребоваться много.

Бывают также ситуации, когда в тестовой системе программа отрабатывает нормально, разработчик переносит ее в продуктивную систему и видит, что имеются серьезные проблемы с производительностью этой программы. В тестовой системе это не проявлялось, потому что объем данных в ней был не такой большой, как в продуктивной системе, или нагрузка на БД была меньше. И опять разработчик возвращается в систему разработки, чтобы оптимизировать программный код. Теперь каждая итерация у него будет занимать еще больше времени, так как, в большинстве случаев, перенос изменений в продуктивную систему сопровождается цепочкой согласований изменений с разными ответственными лицами.

Рис. 1. Системный ландшафт

Оптимизация процесса разработки

Поняв, что теряем много времени на подобные вещи, мы пришли к выводу, что нужно этот процесс оптимизировать: надо уменьшить число итераций по исправлению кода и таким образом сократить общее время разработки (Рис. 2).

Рис. 2. Оптимизация Системного ландшафта

В первую очередь мы обратили внимание на SQL-запросы. Они часто бывают самым слабым местом в коде: либо данные выбираются некорректно, либо выбираются очень медленно.

Те, кто знаком с разработкой на 1С, знают, что там есть инструмент, который называется «Консоль запросов», позволяющий выполнять произвольные запросы напрямую в продуктивной системе без дополнительных разработок. Мы решили, что нам нужен такой же инструмент для SAP, то есть нам требуется инструмент, который бы позволял оперативно тестировать этот запрос на продуктивных данных и сразу же вносить в него корректировки без переноса кода. Этот инструмент дал бы возможность при разработке использовать в коде ABAP-разработки уже полностью протестированный запрос.

Я решил заняться поиском такого инструмента.

Существующие инструменты

Я рассмотрел существующие инструменты SAP по работе с таблицами, в поисках такого, который помог бы с тестированием произвольных запросов в продуктивной системе, – у всех были те или иные недостатки (Рис. 3):

Рис. 3. Недостатки существующих инструментов

  1. Транзакция SE16/SE16N
    • Можно делать выборку только из одной таблицы. Не подходит для запросов с несколькими таблицами.
  2. Транзакция ST04 (Additional functions -> SQL Command Editor)
    • Во-первых, воспринимает только Native SQL-запросы (синтаксис СУБД), что накладывает некоторые неудобства, так как при разработке программ на ABAP для универсальности используются Open SQL-запросы, отличающиеся синтаксисом. Это, впрочем, можно было бы «пережить», если бы не «во-вторых».
    • Во-вторых, работает только в том случае, если в качестве СУБД используется Oracle.
  3. Транзакция SQVI
    • Нельзя соединять таблицы по не ключевым полям.
    • Нельзя составлять запросы с подзапросами.
    • Не отражается текст запроса. Выборка настраивается графически.

Готовые Z-разработки, найденные в интернете, тоже не подходили по различным причинам. В основном, из-за каких-либо существенных ограничений.

В итоге, не найдя подходящего готового инструмента, я решили разработать его сам.

Разрабатываем

Для начала в транзакции SE80 создаем программу ZSQL, GUI-статус MAIN100 с кнопкой «Выполнить» и Экран 0100.

Укрупнённо алгоритм программы выглядит так (Рис. 4):

Рис. 4. Алгоритм программы

Считывание SQL-запроса

Для получения SQL-запроса будем использовать текстовый редактор, который создадим на экране с помощью класса CL_GUI_TEXTEDIT. Для этого добавим на Экран 0100 пустой контейнер с именем MYEDIT, в который будем выводить редактор.

Фрагмент кода, создающий текстовый редактор на экране:

==================

data: g_editor type ref to cl_gui_textedit,

        g_editor_container type ref to cl_gui_custom_container.

  if g_editor is initial.

    create object g_editor_container

      exporting

        container_name = `MYEDIT`

      exceptions

        cntl_error = 1

        cntl_system_error = 2

        create_error = 3

        lifetime_error = 4

        lifetime_dynpro_dynpro_link = 5.

    create object g_editor

      exporting

        parent = g_editor_container

        wordwrap_mode = cl_gui_textedit=>wordwrap_at_fixed_position

        wordwrap_to_linebreak_mode = cl_gui_textedit=>true

      exceptions

        others = 1.

    if sy-subrc <> 0.

      leave program.

    endif.

  endif.

==================

Проверка на допустимый ввод

Введенный запрос необходимо проверить, чтобы исключить возможность выполнения UPDATE / DELETE / INSERT запросов и прочих опасных конструкций. Разрешаем только выполнения SELECT-запросов.

Фрагмент кода, проверяющий запрос:

==================

" Запрещенные слова/символы

"

data: lt_not_allowed_word type ty_simple_tab,

         lt_parsed_sql_line type ty_simple_tab,

         l_error_text(255) type c value 'Вы используете запрещенное слово или символ: '.

field-symbols: <fs_sql_query> type ty_simple_struc,

                        <fs_not_allowed_word> type ty_simple_struc,

                        <fs_parsed_sql_line> type ty_simple_struc.

append `UPDATE` to lt_not_allowed_word.

append `INSERT` to lt_not_allowed_word.

append `DELETE` to lt_not_allowed_word.

append `MODIFY` to lt_not_allowed_word.

append `CALL` to lt_not_allowed_word.

append `PERFORM` to lt_not_allowed_word.

append `COMMIT` to lt_not_allowed_word.

append `INCLUDE` to lt_not_allowed_word.

append `DROP` to lt_not_allowed_word.

append `ALTER` to lt_not_allowed_word.

append `.` to lt_not_allowed_word.

append `"` to lt_not_allowed_word.

"

loop at lt_sql_query assigning <fs_sql_query>.

  " Первым словом первой строки должен быть SELECT

  "

  if sy-tabix = 1.

    refresh lt_parsed_sql_line.

    split <fs_sql_query>-line at space into table lt_parsed_sql_line.

    delete lt_parsed_sql_line where line = ''.

    read table lt_parsed_sql_line assigning <fs_parsed_sql_line> index 1.

    translate <fs_parsed_sql_line>-line to upper case.

    if <fs_parsed_sql_line>-line <> 'SELECT'.

      message 'Запрос должен начинаться с SELECT' type 'I'.

      l_error = 'X'.

      exit.

    endif.

  endif.

  " Проверяем на запрещенные слова

  "

  loop at lt_not_allowed_word assigning <fs_not_allowed_word>.

    find <fs_not_allowed_word>-line in <fs_sql_query>-line ignoring case.

    if sy-subrc = 0.

      concatenate l_error_text ` ` <fs_not_allowed_word>-line into l_error_text.

      message l_error_text type 'I'.

      l_error = 'X'.

      exit.

    endif.

  endloop.

endloop.

==================

Парсинг SQL-запроса

Из введенного SQL-запроса нам необходимо получить список выбираемых полей и таблиц для того, чтобы в дальнейшем на основании этого списка динамически сгенерировать структуру ALV-Grid для вывода результата.

Фрагмент кода, анализирующий запрос:

==================

types: ty_simple_tab type standard table of ty_simple_struc.

types: ty_t_code type standard table of rssource-line.

data lt_sql_query type ty_simple_tab.

       lt_fields type ty_simple_tab,

        lt_tables type ty_simple_tab,

        l_use_cnt(1) type c.

" Анализируем запрос построчно

loop at lt_sql_query assigning <fs_sql_query>.

  " Удаляем нечитаемые спец-символы

  replace all occurrences of con_tab in <fs_sql_query>-line with space.

  concatenate ` ` <fs_sql_query>-line ` ` into <fs_sql_query>-line.

  " Разбиваем строку на отдельные слова

  refresh lt_parsed_sql_line.

  split <fs_sql_query>-line at space into table lt_parsed_sql_line.

  delete lt_parsed_sql_line where line = ''.

  loop at lt_parsed_sql_line assigning <fs_parsed_sql_line>.

    translate <fs_parsed_sql_line>-line to upper case.

    if <fs_parsed_sql_line>-line = 'SELECT'.

      continue.

    endif.

    " Если дошли до * - считаем, что все выбираемые поля получены

    if <fs_parsed_sql_line>-line = '*'.

      l_field_names_obtained = 'X'.

      continue.

    endif.

    " Если дошли до FROM или JOIN - считаем, что все выбираемые поля получены.

    " Следующее слово будет названием таблицы

    if <fs_parsed_sql_line>-line = 'FROM' or <fs_parsed_sql_line>-line = 'JOIN'.

      l_field_names_obtained = 'X'.

      l_is_tabname = 'X'.

      continue.

    endif.

    " Получаем названия полей

    if l_field_names_obtained is initial.

      " Ищем конструкцию COUNT()

      find 'COUNT(' in <fs_parsed_sql_line>-line ignoring case.

      if sy-subrc = 0.

        l_use_cnt = 'X'.

        continue.

      endif.

      " Название поля указано с названием таблицы через ~

      search <fs_parsed_sql_line>-line for '~'.

      if sy-subrc = 0.

        add 1 to sy-fdpos.

      endif.

      append <fs_parsed_sql_line>-line+sy-fdpos to lt_fields.

    endif.

    " Получаем названия таблиц

    if l_is_tabname = 'X'.

      append <fs_parsed_sql_line>-line to lt_tables.

      clear l_is_tabname.

    endif.

  endloop.

endloop.

==================

Выполнение SQL-запроса

Чтобы выполнить наш запрос, воспользуемся оператором generate subroutine pool, который позволяет динамически генерировать временные ABAP-программы на основании переданного в качестве параметра исходного кода, которым мы подготовим из введенного SQL-запроса.

Фрагмент кода, генерирующий ABAP-программу:

==================

types: ty_t_code type standard table of rssource-line.

data: code type ty_t_code,

         prog(8) type c,

         msg(120) type c,

         lt_parsed_sql_line type ty_simple_tab,

         l_sub_order(1) type c.

field-symbols: <fs_sql_query> type ty_simple_struc,

                        <fs_parsed_sql_line> type ty_simple_struc.

append `program z_sql.` to code.

append `form get_data using fs_data type standard table.` to code.

append `try.` to code.

loop at lt_sql_query assigning <fs_sql_query>.

  clear: lt_parsed_sql_line.

  split <fs_sql_query>-line at space into table lt_parsed_sql_line.

  delete lt_parsed_sql_line where line = ''.

  loop at lt_parsed_sql_line assigning <fs_parsed_sql_line>.

    concatenate ` ` <fs_parsed_sql_line>-line ` ` into <fs_parsed_sql_line>-line.

    translate <fs_parsed_sql_line>-line to upper case.

    " добавляем into… только 1 раз, иначе будет добавляться во все подзапросы

    if <fs_parsed_sql_line>-line = ' FROM ' and l_sub_order is initial.

      append `into corresponding fields of table fs_data` to code.

      l_sub_order = 'X'.

    endif.

    append <fs_parsed_sql_line>-line to code.

  endloop.

endloop.

append `.` to code.

append `rollback work.` to code.

append `catch cx_root.` to code.

append `rollback work.` to code.

append `message ``Что-то пошло не так, проверьте запрос`` type ``i``.` to code.

append `endtry.` to code.

append `endform.` to code.

generate subroutine pool code name prog

                                                 message msg.

==================

Вывод результата на экран

Так как состав полей и их тип нам заранее неизвестны, то для получения результата и вывода его на экран нам необходимо динамически сгенерировать внутреннюю таблицу и структуру ALV-Grid на основании выбираемых в запросе полей. Для этого будем использовать метод create_dynamic_table класса cl_alv_table_create.

Фрагмент кода, генерирующий структуру ALV-Grid:

==================

data: ref_table_descr type ref to cl_abap_structdescr,

        lt_tab_struct type abap_compdescr_tab,

        ls_fieldcatalog type slis_fieldcat_alv.

field-symbols: <fs_tab_struct> type abap_compdescr,

                       <fs_tables> type ty_simple_struc,

                       <fs_fields> type ty_simple_struc.

loop at lt_tables assigning <fs_tables>.

  refresh lt_tab_struct.

  " Получаем все поля для выбираемой таблицы

  ref_table_descr ?= cl_abap_typedescr=>describe_by_name( <fs_tables>-line ).

  lt_tab_struct[] = ref_table_descr->components[].

  loop at lt_tab_struct assigning <fs_tab_struct>.

    " если поля нет среди выбираемых в SQL-запросе - не выводим его не экран

    if lines( lt_fields ) > 0.

      read table lt_fields transporting no fields with key line = <fs_tab_struct>-name.

      if sy-subrc <> 0.

        continue.

      endif.

    endif.

    " если поле с таким именем уже есть, то не добавляем повторно

    read table lt_fieldcatalog transporting no fields with key fieldname = <fs_tab_struct>-name.

    if sy-subrc = 0.

      continue.

    endif.

    clear ls_fieldcatalog.

    ls_fieldcatalog-fieldname = <fs_tab_struct>-name.

    ls_fieldcatalog-ref_tabname = <fs_tables>-line.

    append ls_fieldcatalog to lt_fieldcatalog.

  endloop.

endloop.

" В запросе есть конструкция COUNT() – добавляем колонку с именем CNT и типом INT

if l_use_cnt = 'X'.

  clear ls_fieldcatalog.

  ls_fieldcatalog-fieldname = 'CNT'.

  ls_fieldcatalog-seltext_l = 'Кол-во'.

  ls_fieldcatalog-seltext_m = 'Кол-во'.

  ls_fieldcatalog-seltext_s = 'Кол-во'.

  ls_fieldcatalog-datatype = 'INT4'.

  if p_tech_names = 'X'.

    ls_fieldcatalog-seltext_l = 'CNT'.

    ls_fieldcatalog-seltext_m = 'CNT'.

    ls_fieldcatalog-seltext_s = 'CNT'.

    ls_fieldcatalog-reptext_ddic = 'CNT'.

  endif.

  append ls_fieldcatalog to lt_fieldcatalog.

endif.

==================

Фрагмент кода, создающий динамическую таблицу:

==================

data: dyn_table type ref to data,

        dyn_line type ref to data,

        lt_lvc_fieldcatalog type lvc_t_fcat,

        ls_lvc_fieldcatalog type lvc_s_fcat.

field-symbols: <fs_fieldcatalog> type slis_fieldcat_alv.

" Преобразуем данные в другой тип

loop at lt_fieldcatalog assigning <fs_fieldcatalog>.

  clear ls_lvc_fieldcatalog.

  move-corresponding <fs_fieldcatalog> to ls_lvc_fieldcatalog.

  ls_lvc_fieldcatalog-ref_table = <fs_fieldcatalog>-ref_tabname.

  append ls_lvc_fieldcatalog to lt_lvc_fieldcatalog.

endloop.

" Создаем динамически таблицу

call method cl_alv_table_create=>create_dynamic_table

  exporting

    it_fieldcatalog = lt_lvc_fieldcatalog

  importing

    ep_table = dyn_table.

assign dyn_table->* to <fs_data>.

create data dyn_line like line of <fs_data>.

assign dyn_line->* to <fs_wa_data>.

==================


Полный листинг исходного кода программы ZSQL:

==================

type-pools: slis.

types: begin of ty_simple_struc,

            line(255) type c,

          end of ty_simple_struc.

types: ty_simple_tab type standard table of ty_simple_struc.

types: ty_t_code type standard table of rssource-line.

data: g_editor type ref to cl_gui_textedit,

        g_editor_container type ref to cl_gui_custom_container,

        g_ok_code like sy-ucomm,

        p_tech_names(1) type c.

field-symbols:

Ограниченный доступ

Для прочтения полной версии статьи необходимо зайти как зарегистрированный пользователь.

Ключевые слова: SAP ERP
Функциональная область: Информационные технологии / IT, Basis, ABAP
Ролевое назначение: SAP Консультант / Consultant
Комментарии:

Анатолий Халимовский (Рейтинг: 63) 17:55, 14 января 2016

8-/ В системе безопасности появилась "черная дыра"...
13:03, 15 января 2016

Николай Кронский (Рейтинг: 345)

Толя, привет.
Согласен, виден подход программиста но не разработчика...
16:39, 15 января 2016

Руслан Закарьяев (Рейтинг: 406)

Добрый день.
 
Я в статье специально не затрагивал вопросы, связанные с организацией доступа к этому инструменту и данным, потому что, во-первых, основной целью статьи было все таки показать функциональность инструмента; во-вторых, на разных проектах могут быть разные требования к уровню доступа к данным: где-то достаточно ограничить доступ к программе, где-то к таблице, а где-то к конкретным записям таблицы.
 
С точки зрения функциональности этот инструмент не дает большего объема информации, чем, скажем, транзакция SE16N.

Олег Точенюк (Рейтинг: 10233) 15:17, 16 января 2016

Для проверки своих запросов,особенно если есть различные варианты, следует воспользоваться транзакцией SE38: на первом экране нужно перейти по меню: Среда – Примеры – Примеры производительности.
 
Для вывода результата выборки, если необходимо, пишется один ФМ куда передается объявленная таблица, и который в свою очередь, выводит любую таблицу в отдельном всплывающем окне используя вот эти 4 строки:
 
DATA: gc_alv_table TYPE REF TO cl_salv_table.
 
cl_salv_table=>factory( IMPORTING r_salv_table = gc_alv_table
                        CHANGING t_table = lt_ekko[] ).
gc_alv_table->display( ).
 
В предложенном редакторе можно вбивать не только запросы SQL, но и объявлять свои переменные, подпрограммы и т.д. вызывать модули и создавать классы.
 
В общем тоже можно сказать черная дыра, но правда, возможность ввода кода в окна, управляется полномочиями. Опять же можем параллельно проверять производительность участков кода с небольшими изменениями.
 
PS: Что касается еще так называемой черной дыры, ну если у вас абаперы так свободно бегают в тестовую среду с реальными данными, то что вам мешает или скопировать эти данные в соседний мандант системы разработки (верю что тут может быть мало места) или открыть в системе теста возможность создавать локальные программы и уже там, в стандартном SE38, быстро моделировать работу с данными?
16:00, 16 января 2016

Олег Точенюк (Рейтинг: 10233)

Ну т.е. на выходе получается что-то типа такого
 
13:06, 18 января 2016

Руслан Закарьяев (Рейтинг: 406)

Добрый день.
 
Способ, который вы описАли, имеет два существенных недостатка:
 
1. Нет никакой фильтрации введенного кода - это действительно самая настоящая черная дыра. Можно выполнить абсолютно любой АБАП-код, включая UPDATE/DELETE.
 
2. Самое главное. Данный инструмент можно использовать только в той системе, в которой мы можем редактировать код программ. Он не работает, если у системы стоит статус "Неизменяемая". А такой статус стоит у любой продуктивной и тестовой системы. Т.е. теряется вообще вся идея и весь смысл.
 

Скопировать реальные данные в систему разработки не представляется возможным по двум причинам:
 
1. Вы правы: нет места.
2. Из соображений безопасности. В продуктивной и тестовой системах доступ к данным можно контролировать полномочиями, а в системе разработки проверки полномочий обходятся на раз-два.
 
Разрешать в тестовой системе писать код тоже не представляется возможным. Может, в каких-то проектах это практикуется. В наших - нет.
17:56, 20 января 2016

Олег Точенюк (Рейтинг: 10233)

1. Нет такого конечно, но вы то сами делаете разработку, которая с точки зрения системы не совсем кошерная. Далее работать предполагается в системе теста, так что если и удалят что-то то вряд ли это критично-критично. Зато код может быть написан разный + можно быстро проверить скорость выполнения кода при разных модификациях.
 
2. А вас с вашей программой в продуктивную систему пускают? Код редактировать не обязательно, статус системы должен быть не блокированная, полномочия на разработку иметь вроде как не обязательно, добавить разве что надо что-то типа такого:
  authority-check object 'S_DEVELOP'
                  id     'OBJTYPE'   field 'PROG'
                  id     'DEVCLASS'         dummy
                  id     'P_GROUP'          dummy
                  id     'OBJNAME'          dummy
                  id     'ACTVT'     field '02'.
 
3. Ваша программа выбирает данные из таблиц, в тестовой системе которая, где-то равна продуктивной. Тогда о какой безопасности данных мы говорим? Кто помешает вашей разработкой считать данные из любых таблиц? Так что безопасность что тут что там, как сферический код в вакууме.
12:30, 21 января 2016

Руслан Закарьяев (Рейтинг: 406)

1. Работать предполагается не только в системе теста, но и в продуктивной, а в этом случае ваш вариант точно не подходит: никто не даст писать неконтроллируемый код в продуктиве. А на наших проектах и в тестовой системе не дадут этим заниматься.
 
2/3. Да, нашу программу пускают. Конечно, не в том виде, в котором она описана в статье. У нас есть проверка полномочий: доступ к таблицам и даже к отдельным записям ограничен - никаких лишних данных никто не получит.
 

Ваш инструмент тоже очень полезен, но он предназначен немного для других целей.
10:10, 30 мая 2016

Юлия Матченко (Рейтинг: 16)

Олег, у меня в тр.se38 нет возможности вставлять свой текст. Не подскажете, где это можно настроить?
13:46, 30 мая 2016

Олег Точенюк (Рейтинг: 10233)

Ну похоже в новых версиях все, кина не будет. Там в коде просто сейчас поставили:
 
    CALL METHOD CODE_LEFT_EDITOR->SET_READONLY_MODE
      EXPORTING
        READONLY_MODE = 1.
 
И никакой проверки полномочий. Так что данный способ можно сказать закрыт, хотя никто не мешает вам скопировать программу RSHOWTIM в свою и там разрешить редактирование, для внутреннего так сказать использования. Предлагать в энхансменте менять READONLY_MODE = 0, не буду. А то придет Василий и будет сильно расстроен :-)

Михаил Кирилловский (Рейтинг: 38) 16:35, 17 января 2016

А с чего вы взяли, что в ST04 SQL editor заточен исключительно под ORACLE? В среде с DB2 тоже все превосходно работает.
13:07, 18 января 2016

Руслан Закарьяев (Рейтинг: 406)

Добрый день.
 

Взял с того, что для DB2 пункта Additional functions -> SQL Command Editor в ST04 нет. В многочисленных ветках на scn.sap.com говорится то же самое.
 
Вы знаете какой-то другой способ? Поделитесь, пожалуйста.
14:13, 18 января 2016

Михаил Сидорочкин (Рейтинг: 104)

Diagnostics --> SQL Editor (HANA, доступ через ADBC т.е. Native SQL)
18:34, 18 января 2016
ST04 -> Diagnostics -> SQL Command line
 
Плохо ищите.
18:02, 19 января 2016

Руслан Закарьяев (Рейтинг: 406)

Такого пункта в наших проектах я тоже не нашел.
 
Ладно, это была не суть статьи. В любом случае, ST04 не подходит из-за Native SQL.

Шахин Микаилов (Рейтинг: 10) 11:55, 02 февраля 2016

Спасибо автору,
Интересная статья.
Мы для таких вещей используем Hovitaga Report Generator. Многофункционально, легько установит, использоват и главное безопасно.

Антон Сорокин (Рейтинг: 257) 12:56, 02 февраля 2016

>>С точки зрения функциональности этот инструмент не дает большего объема информации, чем, скажем, транзакция SE16N.
 
Не, ну как же. В se16n нет join, это очень существенно. Join - это единственное и главное чего не хватает для удобных выборок.
 
Забавные заказчики, которые пускают это в продуктив :)  В моей практике и se16n не всегда можно запустить :)
15:48, 12 февраля 2016
В стандарте есть уже - SE16H с джойнами (более 3-х лет уже).
Возможности расписаны в 1636416 - CO-OM tools: Functions of transaction SE16H

Юрий Сычов (Рейтинг: 42) 21:59, 16 мая 2016

Знакомый еще в 2009 году соорудил
zaaqb - sql query tool
 
sapnet.ru/viewtopic.php

Любое воспроизведение запрещено.
Копирайт © «Издательство ООО «Эксперт РП»