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

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

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


person Zero    schedule 10.05.2018    source источник


Ответы (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].

Мое заключение:

  • Когда исключение основано на одном поле, работают оба _16 _ / _ 17_. Один может быть лучше другого, в зависимости от используемых вами фильтров.
  • Когда исключение основано на 2 или более полях и у вас нет соединения «многие ко многим» в основном запросе, not exists ( select .. from table where id = a.id or id = b.id or... ) кажется лучшим.
  • В тот момент, когда ваш критерий исключения реализует отношение «многие ко многим» в вашем основном запросе, я бы порекомендовал поискать оптимальный способ реализации нескольких подзапросов вместо этого (даже наличие подзапроса для каждой комбинации ключей и таблиц будет работать лучше, чем соединение многие-ко-многим с 1 хорошим подзапросом, что выглядит хорошо).

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

EDIT2: хотя это немного не по теме, учитывая, что мой вопрос касался подзапросов, я решил, что опубликую обновление. Через год мне пришлось пересмотреть решение, над которым я работал, чтобы расширить его. Я узнал, что правильное исключение соединения работает. Я просто ужасно провалил это в первый раз.

select header~key 
from headers left join items on headers~key = items~key
where items~key is null
person Zero    schedule 14.05.2018

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

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

person Suncatcher    schedule 10.05.2018
comment
Ваш ответ указал мне на возможное решение. В настоящее время я тестирую вариант, в котором используется добавление NOT EXISTS в предложении WHERE. Мне почему-то не сразу пришло в голову, что я могу сравнить там столько полей, сколько захочу. Однако я еще не уверен в производительности, поэтому я постараюсь обновить вопрос, когда у меня будут какие-то результаты. - person Zero; 11.05.2018
comment
@Zero, согласен. Я думаю, что НЕ СУЩЕСТВУЕТ - правильный ответ. Вы можете сравнить несколько полей между основным запросом и подзапросом. Пожалуйста, подумайте о добавлении ответа, чтобы мы могли проголосовать за него. - person Sandra Rossi; 14.05.2018