SemanticException: элемент выбора в позиции 1 в списке выбора не имеет псевдонима при использовании подвыбора JPQL

Данные сущности:

@Entity
@Data
public class Collection {

  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  private Long id;

  private String createdBy;

  @OneToMany(mappedBy = "collection")
  private List<CollectionAccess> collectionAccesses;

}

@Entity
@Data
public class CollectionAccess {

  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  private Long id;

  @ManyToOne
  @JoinColumn(
      foreignKey =
          @ForeignKey(
              value = ConstraintMode.PROVIDER_DEFAULT,
              name = "fk_collectionaccess_collection_collections_id"))
  private Collection collection;

  private Integer accessType;
  private LocalDateTime expirationAtUtc;
}

Данная база данных:

select id, created_by from collection;
+----+------------+
| id | created_by |
+----+------------+
| 40 |   ABC123   |
+----+------------+

select * from collection_access;
+----+-------------+----------------------------+---------------+
| id | access_type | expiration_at_utc          | collection_id |
+----+-------------+----------------------------+---------------+
|  2 |           0 | 2011-12-03 03:15:30.000000 |            40 |
|  3 |           1 | 2011-12-03 03:15:30.000000 |            40 |
+----+-------------+----------------------------+---------------+

Написание этого запроса вызывает SemanticException:

em.createQuery(
          "SELECT t FROM (SELECT c FROM Collection c "
                  + "LEFT JOIN c.collectionAccesses ca WHERE c.id = ?1 "
                  + "AND (c.createdBy = ?2 OR (ca.accessType = ?3 AND ca.expirationAtUtc <= ?4))) t "
                  + "JOIN FETCH t.collectionAccesses ",
          Collection.class)
      .setParameter(1, id)
      .setParameter(2, "ABC123")
      .setParameter(3, 1)
      .setParameter(4, now)
      getSingleResult();


java.lang.IllegalArgumentException: org.hibernate.query.SemanticException: Select item at position 1 in select list has no alias (aliases are required in CTEs and in subqueries occurring in from clause)
    at org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:143) ~[hibernate-core-6.4.4.Final.jar:6.4.4.Final]

Как правильно написать запрос SELECTFROM a subselect в JPQL/Hibernate?

Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
1
0
170
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Вы не можете использовать подзапрос в предложении FROM в JPQL. У вас есть 2 варианта:

  1. использовать собственный запрос
  2. попробуйте переписать запрос, чтобы заменить подзапрос в предложении FROM

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

    em.createQuery(
          "SELECT c FROM Collection c "
                  + "JOIN FETCH c.collectionAccesses ca WHERE c.id = ?1 "
                  + "AND (c.createdBy = ?2 OR c.id = (SELECT c.id FROM Collection c LEFT JOIN c.collectionAccesses ca WHERE ca.accessType = ?3 AND ca.expirationAtUtc <= ?4))",
          Collection.class)
      .setParameter(1, id)
      .setParameter(2, "ABC123")
      .setParameter(3, 1)
      .setParameter(4, now)
      .getSingleResult();

В этом случае вы не можете избежать двух запросов выбора. Попробуйте выполнить это в консоли sql, и вы увидите, что получили одну строку:

SELECT * FROM collection c LEFT JOIN collection_access ca ON c.id = ca.collection_id WHERE c.id = 40 AND (c.created_by = 'DUMMY' OR (ca.access_type = 1 OR ca.expiration_at_utc <= now()))

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

em.createQuery(
          "SELECT c FROM Collection c "
                  + "JOIN FETCH c.collectionAccesses ca WHERE c.id = ?1 "
                  + "AND (c.createdBy = ?2 OR c.id IN (SELECT c.id FROM Collection c LEFT JOIN c.collectionAccesses ca WHERE ca.accessType = ?3 AND ca.expirationAtUtc <= ?4))",
          Collection.class)
      .setParameter(1, id)
      .setParameter(2, "ABC123")
      .setParameter(3, 1)
      .setParameter(4, now)
      .getResultList();

В этом случае getResultList() вернет массив объектов, благодаря чему вы избежите исключения NoResultException, а также получения нескольких результатов по запросу.

Привет @user25907346, есть ли какой-либо документ/сообщение, указывающее, что подзапрос недействителен в предложении FROM в JPQL?

SoT 02.07.2024 05:01

требование здесь: stackoverflow.com/questions/78605966/…

SoT 02.07.2024 05:07

Здесь написано, что подзапросы можно использовать в предложениях WHERE и HAVING: openjpa.apache.org/builds/1.2.3/apache-openjpa/docs/… Из моего опыта были случаи, когда мне это действительно было нужно подзапросы в предложении FROM, но не смог этого добиться. Это работало, если я не переписал запрос. Кроме того, я отредактировал свой ответ, чтобы он соответствовал вашему вопросу, надеюсь, это поможет.

Akira 02.07.2024 20:22

Также еще одна статья: thorben-janssen.com/jpql/#subselects

Akira 02.07.2024 20:51

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