Работа в отчётах с параметром SELECT-OPTIONS проста.
Сначала определяем:
select-options: s_anln1 for anla-anln1.
Потом используем:
select * from anla into table gt_report where anln1 in s_anln1.
Всё просто на первый взгляд. При таком коде внутри Open SQL происходит простая работа: OpenSQL трансформируется в NativeSQL, а там подобной конструкции нет. Поэтому фактический запрос превращается приблизительно в следующее:
select * from dbchema.anla where anln1 = ‘1’ or anln1 = ‘2’ or anln1 = ‘3’;
И если бы забьём очень много значений в поле выбора, то длина получающегося в результате SQL запроса будет расти линейно. Именно где-то тут я встретился с узким местом, в котором меня стукнули по носу динамической ошибкой DBIF_RSQL_INVALID_RSQL. Интересно, а почему не SAPSQL_STMNT_TOO_LARGE?
В моём случае это примерно 9980 значений типа ANLN1. Это эмпирическое число видимо будет разниться от системе к системе, от используемого типа данных и прочих условий. И как его гарантированно предсказать в общем случае?
Есть в недавней игре Saints Row: Gat Out of Hell одно достижение: десять раз стукнуться головой о потолок.
Как быть?
В моём случае я решил, что пользователю не следует выдумывать себе сценарии, в которых необходимо вводить десять тысяч значений в поле выбора. Ибо нефиг. Для красоты можно разве что поставить проверку на экране выбора, чтобы в эти очень редкие моменты красиво выругаться. Динамическая ошибка – это не красиво.
FOR ALL ENTRIES IN itab
решает эту проблему.
Согласен, решает. Когда работает FOR ALL ENTRIES при необходимости запрос делится на порции.
Вот только ITAB ещё надо будет как-то заполнить. А чтобы ITAB заполнить быстро и просто снова надо снова использовать IN S_ANLN1.
Получается так или иначе надо обращаться за LOOP AT S_ANLN1. А если мы это делаем, уже и смысла в FOR ALL ENTRIES чуть меньше.
Вы хотите сказать что конструкции
LOOP AT S_ANLN1
SELECT
ENDLOOP.
равнозначна
FOR ALL ENTRIES
Ну результат будет примерно одинаковым, с некоторыми упущениями в части производительности:
1000 запросов по 1 ключу (LOOP) должны работать в целом медленнее, чем 10 запросов по 100 ключей (FOR ALL).
Но можно же и что-то вроде:
loop at S_ANLN1.
if S_ANLN1-OPTION = ‘EQ’ and S_ANLN1-SIGN = ‘I’ .
append S_ANLN1-LOW to ITAB.
else.
… вот тут уже может что-то начаться сложное, так как есть в природе разное…
endif.
endloop.
select * for all entries in ITAB.
Но не следует забывать что FOR ALL ENTRIES работает как SELECT DISTINCT, т.е. если например вы выбираете позиции к документам по номерам документов есть риск потери данных. Ну это вопрос понимания программистом чего ему нужно :) Можно использовать FOR ALL ENTRIES используя полный ключ.
Я бы например если бы использовал RANGE в запросе, то поделил примерно по 2000 записей. Тут дело не в количестве записей в RANGE а ограничение на размер запроса. В MSSQL и ORACLE это ограничение составляет 64Kb
А еще я бы задумался над тем какой сервер работает быстрее :) Если сервер БД то тогда однозначно использовал бы RANGE, если application сервер, то тут могут быть варианты :)
P.S. Ну еще в рекомендациях SAP по производительности есть совет который в некоторых местах переходит в приказ :) Старайтесь уменьшить трафик между сервером БД и сервером приложений :)