在 JPQL 中可以选择 EXISTS() 吗?

Posted

技术标签:

【中文标题】在 JPQL 中可以选择 EXISTS() 吗?【英文标题】:Is Select EXISTS() possible in JPQL? 【发布时间】:2011-10-11 20:33:21 【问题描述】:

我正在尝试运行一个查询来检查某些条件是否为真,并返回一个简单的布尔结果作为输出。有点棘手的是,其中一个条件是测试一组条件是否没有返回结果。

我目前使用 JPA-2.0 和 hibernate 作为我的提供程序,由 mysql 提供支持。我得到了一个在 MySQL 中运行良好的示例查询,但是当试图让它在 JPQL 中运行时它失败了。 MySQL 查询看起来有点像这样:

Select exists(Select statement with criteria) 
  or not exists(Select statement with criteria);

我也使用 CASE 得到了相同的输出,但 JPQL 不支持该语句。

无论如何,当我尝试在 JPQL 中使用类似的查询时,我得到了错误:

“子树的意外结束”

据我了解,这意味着查询中缺少某些内容。有谁知道如何解决它?

【问题讨论】:

【参考方案1】:

您的括号不匹配。尝试删除not 之前的那个(并且第一个周围的存在):

select exists(Select statement with criteria) 
  or not exists(Select statement with criteria);

exists() 周围不需要括号

【讨论】:

感谢您指出这一点,但括号或否查询在 JPQL 中仍然不起作用。 openjpa.apache.org/builds/1.2.0/apache-openjpa-1.2.0/docs/… 所以根据文档,至少存在部分是正确的。 “exists_expression ::= [NOT] EXISTS(子查询)”【参考方案2】:

这个答案已经过时了。请参考Rene Link的正确答案


不,这是不可能的。

请参阅 oracle 的 JPQL BNF 文档。

simple_cond_expression ::= 比较表达式 |之间的表达式 |像表达式 | in_表达式 | null_comparison_expression | empty_collection_comparison_expression |集合成员表达式 | exists_expression

exists_expression ::= [NOT] EXISTS(子查询)

【讨论】:

【参考方案3】:

或者,您可以使用select count(...) 并测试它是否返回0。这应该几乎同样有效,无需编写更多代码(事实上,查询本身可能看起来更简单)。

【讨论】:

不一定。 exists(...) 可能会在找到第一个结果后存在。 count(...) 将不得不扫描更多的索引/表行以确定实际计数。 @KonradGarus:不过,这并不重要,count(..) 是唯一适用于 JPQL 的解决方案。所以,当生活给你柠檬时......【参考方案4】:

您可以使用case expression 进行布尔查询。

从 JPA 2.0 (Java EE 6) 开始,您可以 create a TypedQuery 。

String query = "select case when (count(*) > 0)  then true else false end from ......"
TypedQuery<Boolean> booleanQuery = entityManager.createQuery(query, Boolean.class);
boolean exists = booleanQuery.getSingleResult();

在 JPA 1.0 (Java EE 5) 中,您必须使用无类型查询。

Query booleanQuery = entityManager.createQuery(query);
boolean exists = (Boolean) booleanQuery.getSingleResult();

【讨论】:

更易读的方式是:"select (count(*) > 0) from ..." @Reda 这仍然会搜索整个索引/表,尽管数据库可以并且应该在找到第一个结果后停止。 @T3rm1 是的,你是对的,但不幸的是我不知道是否有其他解决方案【参考方案5】:

在一个项目中使用

    <dependency>
        <groupId>org.hibernate</groupId>
        <artifactId>hibernate-core</artifactId>
        <version>4.2.4.Final</version>
    </dependency>
    ...

我成功使用了一个

exists(select s.primaryKey from Something s)

条款。所以它可能已经改变了。它也可能是 Hibernate 专有的。由于很多人使用 Hibernate 作为持久性提供程序,我想我可以在这里添加它。

【讨论】:

【参考方案6】:

在一个使用 Hibernate 5.2(支持 JPA 2.1)和 Spring Data Jpa 2.0.6 的项目中,我成功地使用了这个 JPQL 查询:

@Query("SELECT COUNT(c) > 0 FROM Contract c WHERE c.person.id = :pid")
Boolean existContractForPerson(@Param("pid") Long personId);

在日志中,我读到生成的本机查询如下:

select count(contract0_.contract_id)>0 as col_0_0_ from contracts contract0_ where contract0_.fk_person_id=?

【讨论】:

但是为什么要计算一个你不会使用的计数呢?为什么不尝试在限制范围内选择一个,那对您的数据库来说工作量会减少 @Amalgovinus JPQL 本身不支持 LIMIT 操作。有关 JPA 和 JPQL 的更多信息,请点击此处:(en.wikibooks.org/wiki/Java_Persistence) (en.wikibooks.org/wiki/Java_Persistence/JPQL) 此外,Entity Manager 提供了一个 API,可用于限制任何 JPQL 查询的结果。这已经在这里得到了回答:(***.com/questions/20679237/jpql-limit-query) (***.com/questions/3479128/…) 在这种情况下,对于我之前使用的示例,我将使用不同的查询:SELECT c FROM Contract c WHERE c.person.id = :pid,我会将结果限制为 1,使用:@ 987654328@【参考方案7】:

DB 不计算所有记录更有效。创建原生查询

Spring-Data-JPA

@Query(value = ".....", nativeQuery = true)

或 JPA:

@NamedNativeQuery(name=.., query="..", resultClass=..)

【讨论】:

你在用理论效率换取潜在的代码破坏,因为本机查询语法要到运行时才会验证。

以上是关于在 JPQL 中可以选择 EXISTS() 吗?的主要内容,如果未能解决你的问题,请参考以下文章

在 JPQL 查询中检查集合上的 NULL 吗?

我可以将 JPQL 的结果限制为只返回一个结果吗?

JPQL 选择内部选择

我可以限制使用 JPQL 命名查询的 Spring Data 查询方法的查询结果吗?

可以在一个 JPQL 查询中传递多个命名实体图?

在 JPQL 中选择每辆车的首次预订