Выберите, где несколько полей не в подзапросе (исключая объединение)
У меня есть требование вытащить записи, которые не имеют истории в таблице архива. 2 поля одной записи необходимо проверить в архиве.
В техническом смысле мое требование - это левое соединение, где правая сторона равна нулю (иначе говоря, исключающее соединение), которое в abap openSQL обычно реализуется так (для моего сценария в любом случае):
Select * from xxxx //xxxx is a result for a multiple table join
where xxxx~key not in (select key from archive_table where [conditions] )
and xxxx~foreign_key not in (select key from archive_table where [conditions] )
Эти 2 поля также проверяются с помощью еще 2 таблиц, так что это будет означать всего 6 подзапросов.
Механизмы баз данных, с которыми я работал ранее, обычно имели несколько методов для решения таких проблем (например, исключение соединения или внешнего применения).
В этом конкретном случае я буду пытаться использовать логику ABAP с "для всех записей", но я все же хотел бы знать, возможно ли использовать результаты подзапроса для проверки более чем одного поля или использовать другую форму исключая логику объединения нескольких полей с использованием SQL (без привлечения сервера приложений).
2 ответа
Я протестировал довольно много вариантов подзапросов в жизненном цикле создаваемой мной программы. NOT EXISTS
с проверкой нескольких полей (сокращенный пример ниже) для исключения на основе 2 ключей работает в некоторых случаях. Производительность приемлема (время обработки около 5 секунд), хотя она заметно медленнее, чем тот же запрос, если исключить на основе 1 поля.
Select * from xxxx //xxxx is a result for a multiple table inner joins and 1 left join ( 1-* relation )
where NOT EXISTS (
select key from archive_table
where key = xxxx~key OR key = XXXX-foreign_key
)
РЕДАКТИРОВАТЬ: С изменением требований (для дополнительной фильтрации) многое изменилось, так что я решил обновить это. Конструкция, которую я пометил как XXXX
в моем примере содержалось единственное левое соединение (где отношение основной к вторичной таблице 1-*
) и это оказалось относительно быстро.
Вот где контекст становится полезным для понимания проблемы:
- Начальное требование: вытащить все
vendors
без учета финансовых данных в 3 таблицах. - Дополнительные требования: также исключать на основе альтернативных
payers
(1-*
отношения). Это то, на чем основан пример выше. - Дополнительные требования: также исключать на основе альтернативных
payee
(*-*
отношения междуpayer
а такжеpayee
).
Соединение "многие ко многим" экспоненциально увеличило количество записей в конструкции, которую я обозначил XXXX
что, в свою очередь, производит много ненужной работы. Например: один клиент с 3 payers
и 3 payees
получается 9 строк, в общей сложности 27 полей для проверки (по 3 на строку), когда в действительности существует только 7 уникальных значений.
На этом этапе перемещение левосторонних таблиц из основного запроса в подзапросы и их разбиение дали значительно лучшую производительность. чем любые более разумные альтернативы.
select * from lfa1 inner join lfb1
where
( lfa1~lifnr not in ( select lifnr from bsik where bsik~lifnr = lfa1~lifnr )
and lfa1~lifnr not in ( select wyt3~lifnr from wyt3 inner join t024e on wyt3~ekorg = t024e~ekorg and wyt3~lifnr <> wyt3~lifn2
inner join bsik on bsik~lifnr = wyt3~lifn2 where wyt3~lifnr = lfa1~lifnr and t024e~bukrs = lfb1~bukrs )
and lfa1~lifnr not in ( select lfza~lifnr from lfza inner join bsik on bsik~lifnr = lfza~empfk where lfza~lifnr = lfa1~lifnr )
)
and [3 more sets of sub queries like the 3 above, just checking different tables].
Мой вывод:
- Когда исключение основано на одном поле, оба
not in
/not exits
Работа. Один может быть лучше другого, в зависимости от используемых вами фильтров. - Когда исключение основано на 2 или более полях, и у вас нет соединения "многие ко многим" в основном запросе,
not exists ( select .. from table where id = a.id or id = b.id or... )
кажется лучшим. - В тот момент, когда ваши критерии исключения реализуют отношение "многие ко многим" в вашем основном запросе, я бы порекомендовал вместо этого искать оптимальный способ реализации нескольких подзапросов (даже если подзапрос для каждой комбинации таблицы ключей будет работать лучше, чем соединение "многие ко многим" с одним хорошим подзапросом, который выглядит хорошо).
В любом случае, любое дополнительное понимание этого приветствуется.
если можно использовать результаты подзапроса для проверки более чем одного поля или использовать другую форму исключения логики соединения для нескольких полей
Нет, невозможно проверить два столбца в подзапросе, как ясно сказано в справке SAP:
Предложения в подзапросе subquery_clauses должны составлять скалярный подзапрос.
Скаляр здесь ключевое слово, т.е. он должен возвращать ровно один столбец.
Ваш подзапрос может иметь многостолбцовый ключ, и такой синтаксис вполне допустим:
SELECT planetype, seatsmax
FROM saplane AS plane
WHERE seatsmax < @wa-seatsmax AND
seatsmax >= ALL ( SELECT seatsocc
FROM sflight
WHERE carrid = @wa-carrid AND
connid = @wa-connid )
однако вы говорите, что эти два поля должны быть проверены по разным таблицам
Эти 2 поля также проверяются с помощью еще двух таблиц
так что дело не в тебе. Ваш единственный выбор, кажется, мульти-соединение.
PS FOR ALL ENTRIES
не поддерживает логику отрицания, вы не можете просто использовать какой-то тип NOT IN FOR ALL ENTRIES, это будет не так просто.