Как объединения в корневом подзапросе влияют на результирующий набор запроса JPQL или SQL?

#java #sql #jpql #criteria-api #jpa-2.1

#java #sql #jpql #критерии-api #jpa-2.1

Вопрос:

Это может быть вопрос JPQL или вопрос SQL, но поскольку он был получен при чтении примера критериев в спецификации JPA. Я также помечаю его JPA и Criteria API. Я думаю, проблема в том, что я не понимаю, как работают связанные с SQL подзапросы.

Позвольте мне начать со спецификации JPA. раздел 6.5.12, подзапросы, пример 4: особый случай, в котором говорится,

Обратите внимание, что объединения, включающие производный корень подзапроса, не влияют на условия соединения содержащего запроса. Таким образом, следующие два определения запроса отличаются по семантике:

 CriteriaQuery<Order> q = cb.createQuery(Order.class);
Root<Order> order = q.from(Order.class);
Subquery<Integer> sq = q.subquery(Integer.class);
Root<Order> orderSub = sq.correlate(order);
Join<Order,Customer> customer = orderSub.join(Order_.customer);
Join<Customer,Account> account = customer.join(Customer_.accounts);
sq.select(account.get(Account_.balance));
q.where(cb.lt(cb.literal(10000), cb.all(sq)));
  

и

 CriteriaQuery<Order> q = cb.createQuery(Order.class);
Root<Order> order = q.from(Order.class);
Join<Order,Customer> customer = order.join(Order_.customer);
Subquery<Integer> sq = q.subquery(Integer.class);
Join<Order,Customer> customerSub = sq.correlate(customer);
Join<Customer,Account> account = customerSub.join(Customer_.accounts);
sq.select(account.get(Account_.balance));
q.where(cb.lt(cb.literal(10000), cb.all(sq)));
  

Первый из этих запросов вернет заказы, которые не связаны
с клиентами, тогда как второй — нет. Соответствующий Java
Запросы на языке запросов на постоянство следующие:

 SELECT o
FROM Order o
WHERE 10000 < ALL (
    SELECT a.balance
    FROM o.customer c JOIN c.accounts a)
  

и

 SELECT o
FROM Order o JOIN o.customer c
WHERE 10000 < ALL (
    SELECT a.balance
    FROM c.accounts a)
  

Второй запрос кажется простым, но первый сложно визуализировать.

Мое понимание коррелированного подзапроса заключается в том, что он зависит от внешнего запроса; он использует данные внешнего запроса. Это не зависит от внешнего запроса. Он выполняется один раз для каждой выбранной строки из внешнего запроса.

В обоих запросах заказы выбираются во внешнем запросе. В первом запросе для каждого выбранного порядка из внешнего запроса выполняется следующий подзапрос:

 SELECT a.balance FROM o.customer c JOIN c.accounts a
  

Интуиция подсказывает мне, что клиент, связанный с записью заказа, связан с учетной записью. Следовательно, подзапрос вернет остатки по всем счетам, связанным с конкретным клиентом, который связан с текущей записью заказа.

Я прав или нет? Похоже, я ошибаюсь, согласно приведенному выше примеру, который, опять же, говорит,

"Note that joins involving the derived subquery root do not affect the join conditions of the containing query," и, "The first of these queries will return Orders that are not associated with customers..."

Таким образом, подзапрос не возвращает остатки на счетах клиента, связанные с Заказом? Какие остатки на счетах вместо этого возвращаются? Как правильно это увидеть? У меня голова идет кругом.

Комментарии:

1. У ваших join s нет on предложения, поэтому трудно следить за запросами.

2. Я не хочу изменять запросы, потому что они являются примерами, которые исходят прямо из спецификации JPA 2.1.

Ответ №1:

Первый запрос:

 SELECT o
FROM Order o
WHERE 10000 < ALL (
    SELECT a.balance
    FROM o.customer c JOIN c.accounts a)
  
  1. Сначала выполняется внешний запрос. Внешний запрос выбирает все заказы, включая заказы, которые не связаны с клиентом (например, заказы, выполненные там, где покупатель решил не регистрироваться в качестве клиента).
  2. Затем подзапрос выполняется для каждой записи, выбранной во внешнем запросе.

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

    • Если подзапрос возвращает нулевые строки (что произошло бы в этом примере, если с заказом не связан клиент), условие ALL принимает значение TRUE, и строка включается в результат.

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

Второй запрос:

 SELECT o
    FROM Order o JOIN o.customer c
    WHERE 10000 < ALL (
        SELECT a.balance
        FROM c.accounts a)
  
  1. Сначала выполняется внешний запрос. Внешний запрос выбирает только заказы, связанные с клиентами.

  2. Затем подзапрос выполняется для каждой строки.

    • Если клиент, связанный с заказом, имеет одну или несколько учетных записей, а все балансы на счетах <10000, условие ALL будет оценено как true, и строка во внешнем запросе будет включена в результирующий набор.

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

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