Выберите, где несколько полей не в подзапросе (исключая объединение) - PullRequest
0 голосов
/ 10 мая 2018

У меня есть требование извлекать записи, которые не имеют истории в архивной таблице. 2 поля одной записи необходимо проверить в архиве.

В техническом смысле мое требование - это левое соединение, где правая сторона равна нулю (a.k.a. исключающее соединение), которое в 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 с «для всех записей», но Я все еще хотел бы знать, возможно ли использовать результаты подзапроса для проверки более 1 поле или используйте другую форму исключения логики соединения для нескольких полей с использованием SQL (без участия сервера приложений).

Ответы [ 2 ]

0 голосов
/ 14 мая 2018

Я протестировал довольно много вариантов подзапросов в жизненном цикле программы, которую я создавал. 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 
) 

EDIT: С изменением требований (для дополнительной фильтрации) многое изменилось, поэтому я решил обновить это. Конструкция, которую я пометил как 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... ) представляется наилучшим.
  • В тот момент, когда ваши критерии исключения реализуют отношение «многие ко многим» в вашем основном запросе, я бы порекомендовал вместо этого искать оптимальный способ реализации нескольких подзапросов (даже если иметь подзапрос для каждой комбинации таблицы ключей, работать лучше, чем соединение «многие ко многим» с одним хорошим подзапросом, что выглядит неплохо).

В любом случае, любое дополнительное понимание этого приветствуется.

0 голосов
/ 10 мая 2018

если возможно использовать результаты подзапроса для проверки более чем 1 поле или использовать другую форму исключения логики соединения для нескольких поля

Нет, невозможно проверить два столбца в подзапросе, поскольку Справка 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 поля также проверяются по двум дополнительным таблицам

так что дело не в тебе. Кажется, ваш единственный выбор - мульти-соединение.

P.S. FOR ALL ENTRIES не поддерживает логику отрицания, вы не можете просто использовать какой-то тип NOT IN FOR ALL ENTRIES, это будет не так просто.

...