SELECT SINGLE и UP TO 1 ROWS

Казалось бы, выборка единственной записи из таблицы довольно простая и логически понятная операция, однако все еще частой ошибкой находимой на code-review является следующее предупреждение Code Inspector’a:

Syntax check warning

In «SELECT SINGLE …», the WHERE condition for a key field does not test for equality or the FROM clause contains a join. This means the result is possibly not unique. Internal message code: MESSAGE GSB

Deactivatable using pragma ##WARN_OK. Message Code WRN 1305

Далее рассмотрим что это такое и почему это не нужно игнорировать.

Выборка с указанием полного ключа

Однозначное определение записи в таблице может быть выполнено только при передаче полного ключа таблицы.

Либо через цикл:

Но чтобы более точно передать намерение в коде о выборке единственной записи из таблицы, следует использовать либо SELECT SINGLE и тогда результат формируется в виде структуры:

Либо использовать дополнение UP TO 1 ROWS в цикле:

Либо тоже дополнение без цикла и тогда получаем табличный результат, но с одной единственной строкой:

Не следует использовать FAE и UP TO 1 ROWS:

  • If the addition FOR ALL ENTRIES is also specified, all selected rows are initially read into a system table and the addition UP TO n ROWS only takes effect during the passing from the system table to the actual target area. This can produce unexpected memory bottlenecks.

Выборка с указанием частичного ключа

Возвращаясь к рассматриваемой ошибке в Code Inspector-е, одна возникает в случае использования SELECT SINGLE с указанием не всех полей первичного ключа таблицы.

Подобный код может быть логичен с точки зрения разработчика если он точно знает что структура таблицы и содержащихся в ней данных позволяет выбрать уникальную запись по неполному ключу. Однако разработчик не всегда может быть уверенным на 100% что структура хранимых в таблице данных не поменяется (особенно для custom таблиц) и его код не перестанет работать в будущем.

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

Кроме того тут следует быть внимательным в случае использования конструкции UP TO 1 ROWS, несмотря на семантику выбора единственной записи, никакого предупреждения мы не увидим в случае указания неполного ключа.

Относительно безопасным решением в данном случае является выборка с использованием UP TO 1 ROWS и указанием порядка сортировки в дополнении ORDER BY по первичному ключу:

Однако дополнение не может быть использовано в случае JOIN или при использовании PATH EXPRESSIONS. Кроме того там еще много других ограничений. Соответственно ключевые поля лучше указывать вручную:

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

Указать ORDER BY в SELECT SINGLE не позволит синтаксис, просто потому что это противоречит назначению данной конструкции.

Проверка существования записи в таблице

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

Code-Inspector продолжит ругаться. Соответственно чтобы QA-менеджер (ревьювер) не обратил внимание на данную ошибку, мы либо можем воспользоваться следующей конструкцией (ABAP 7.40 SP5+):

И тогда Code-Inspector не покажет ошибку (кажется эта проверка была исправлена только в 7.50, в ABAP Platform 1909 она точно исчезла).

Либо воспользоваться прагмой для сокрытия предупреждения (желательно с комментарием почему применили прагму):

Либо если такие прагмы запрещены, должны переделать запрос на использование дополнения UP TO 1 ROWS.

Экзотические варианты

Еще одним вариантом без использования дополнительных переменных может быть использование агрегата COUNT( * ), однако производительность такого варианта может быть ниже, т.к. СУБД будет вынуждена не просто взять запись, а еще выполнить подсчёт записей.

Можно еще так, но с точки зрения семантики выглядит странно:

Будет преобразовано в NativeSQL:

Еще экзотические варианты:

 

Добавить комментарий

Ваш адрес email не будет опубликован.