Выберите, где несколько полей не в подзапросе (исключая объединение)

У меня есть требование вытащить записи, которые не имеют истории в таблице архива. 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, это будет не так просто.

Другие вопросы по тегам