Данные сущности:
@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]
Как правильно написать запрос SELECT
FROM
a subselect
в JPQL/Hibernate?
Вы не можете использовать подзапрос в предложении FROM в JPQL. У вас есть 2 варианта:
Однако, проанализировав ваш запрос, я не совсем понимаю, зачем вам этот подвыбор. Я думаю, что это сработает, если сделать следующее:
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, а также получения нескольких результатов по запросу.
требование здесь: stackoverflow.com/questions/78605966/…
Здесь написано, что подзапросы можно использовать в предложениях WHERE и HAVING: openjpa.apache.org/builds/1.2.3/apache-openjpa/docs/… Из моего опыта были случаи, когда мне это действительно было нужно подзапросы в предложении FROM, но не смог этого добиться. Это работало, если я не переписал запрос. Кроме того, я отредактировал свой ответ, чтобы он соответствовал вашему вопросу, надеюсь, это поможет.
Также еще одна статья: thorben-janssen.com/jpql/#subselects
Привет @user25907346, есть ли какой-либо документ/сообщение, указывающее, что подзапрос недействителен в предложении FROM в JPQL?