如何对JPA查询的子查询强加LIMIT?

时间:2011-12-18 22:50:10

标签: jpa subquery jpql

是否可以在JPA查询中对子查询施加LIMIT?

我在纯SQL中有以下查询

select * from ipinfo 
where RangeEnd < (select RangeStart from ipinfo where RangeStart >= 1537022421 order by RangeStart asc limit 1) and (1537022421 <= RangeEnd)
ORDER BY RangeEnd desc
limit 1

将它直接转换为JPQL我有类似

的东西
select obj from IpInfo obj
where obj.rangeEnd < (select obj2.rangeStart from IpInfo obj2 where obj2.rangeStart >= ?1 order by obj2.rangeStart asc limit 1) and (?1 <= obj.rangeEnd)
ORDER BY obj.rangeEnd desc
limit 1

由于我无法在JPQL中使用LIMIT,因此我必须使用setMaxResults(1)。但是子查询呢?

更新

我现在决定使用@NamedNativeQuery但它是特定于数据库的代码。如果你们可以推荐纯粹的JPA解决方案,我会非常感激。

3 个答案:

答案 0 :(得分:2)

我不知道如何使用JPQL,但你可以使用Criteria API处理它,至少我很确定我们可以用Hibernate条件子查询来做到这一点所以我想即使是JPA也可以JPA标准api对我来说有点混乱。

检查一下: JPA 2.0, Criteria API, Subqueries, In Expressions

无论如何,你甚至不需要对子查询进行限制。

您的原始查询: 从ipinfo中选择RangeStart,其中RangeStart&gt; = 1537022421 order by RangeStart asc limit 1 您似乎想要ipinfo列表的最小RangeStart,它刚好超过给定值。 min函数已经完成了。

你可以简单地使用这样的子查询:

select min(RangeStart) from ipinfo where RangeStart >= 1537022421

即使您需要在子查询中返回其他ipinfo,也可以使用以下内容完成:

select RangeEnd, anything,blabla from ipinfo where RangeStart = (
    select min(RangeStart) from ipinfo where RangeStart >= 1537022421
)

答案 1 :(得分:0)

当前无法通过JPQL添加LIMITmaxResults)或OFFSETstartIndex),也无法在JPA子查询上添加。有一个开放的JPA票证可以添加此功能:

https://github.com/eclipse-ee4j/jpa-api/issues/88

答案 2 :(得分:0)

对此没有 pure JPA解决方案。您可以利用在SQL查询生成期间运行的自定义 SQL函数。所有JPA提供程序都以一种或另一种方式支持类似的东西。

如果您不想自己实现它,或者甚至不想使用适当的API来构造此类查询,那么我只能向您推荐我实现的名为Blaze-Persistence的库。

以下是展示带有子查询的限制/偏移量用例的文档:https://persistence.blazebit.com/documentation/1.2/core/manual/en_US/index.html#pagination

使用查询生成器API,您的查询可能如下所示:

criteriaBuilderFactory.create(entityManager, IpInfo.class)
  .where("rangeEnd").lt()
    .from(IpInfo.class, "subInfo")
    .select("subInfo.rangeStart")
    .where("subInfo.rangeStart").geExpression("1537022421")
    .orderByAsc("subInfo.rangeStart")
    .setMaxResults(1)
  .end()
  .where("1537022421").leExpression("rangeEnd")
  .orderByDesc("rangeEnd")
  .setMaxResults(1)

从本质上讲,它归结为使用由Blaze-Persistence注册的LIMIT SQL函数。因此,当您使用EntityManagerFactory引导Blaze-Persistence时,您甚至应该能够像这样使用它

entityManager.createQuery(
    "select * from ipinfo where RangeEnd < LIMIT((" +
    "  select RangeStart " +
    "  from ipinfo " +
    "  where RangeStart >= 1537022421 " +
    "  order by RangeStart asc" +
    "),1) " +
    "and (1537022421 <= RangeEnd)" +
    "ORDER BY RangeEnd desc"
).setMaxResults(1)

如果您正在使用EclipseLink,则此类函数的调用约定看起来像OPERATOR('LIMIT', ...)