在 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() 吗?的主要内容,如果未能解决你的问题,请参考以下文章