Hibernate Criteria API - HAVING子句可以解决

时间:2021-01-01 20:09:37

I've written a query using Hibernate Criteria API to grab a summation of a particular value, now I need to be able to restrict the result to rows where that sum is greater or equal to a particular value.

我使用Hibernate Criteria API编写了一个查询来获取特定值的总和,现在我需要能够将结果限制为该总和大于或等于特定值的行。

Normally I would use a HAVING clause in my SQL to do this, but the Criteria API doesn't seem to support that at this moment.

通常我会在我的SQL中使用HAVING子句来执行此操作,但此时Criteria API似乎不支持。

In raw SQL this is what I need it to do:

在原始SQL中,这是我需要它做的:

SELECT user_pk, sum(amount) as amountSum
FROM transaction
GROUP BY user_pk
HAVING amountSum >=50;

One work-around that I thought of is to use a subquery in the FROM clause that grabs this summation value and use an outer query to restrict it using a WHERE clause.

我想到的一种解决方法是在FROM子句中使用子查询来获取此求和值,并使用外部查询来使用WHERE子句来限制它。

So, in raw SQL it will look something like:

因此,在原始SQL中,它看起来像:

SELECT user_pk, amountSum
FROM (SELECT user_pk, sum(amount) as amountSum
      FROM transaction
      GROUP BY user_pk)
WHERE amountSum > 50;

Can anyone point me in the right direction as to how I could write this using Criteria API, or any other suggestions/work-arounds I can use to solve the HAVING issue?

任何人都可以指出我是如何使用Criteria API,或者我可以用来解决HAVING问题的任何其他建议/解决方案来编写这个的正确方向?

This is the Criteria API code I have for the above example

这是我在上面的示例中使用的Criteria API代码

DetachedCriteria criteria = DetachedCriteria.forClass(Transaction.class,"transaction");
criteria.setProjection(criteria.setProjection(Projections.projectionList().add(
        Projections.groupProperty("user.userPK").as("user_pk")).add(
            Projections.sum("transaction.amount").as("amountSum")));

Thanks!

3 个解决方案

#1


I don't know of a way for Hibernate/NHibernate to use a subquery in the FROM clause but you can use them in the WHERE clause. Apologies for any Java/Hibernate code mistakes, I am more familiar with C#/NHibernate.

我不知道Hibernate / NHibernate在FROM子句中使用子查询的方法,但您可以在WHERE子句中使用它们。对任何Java / Hibernate代码错误表示歉意,我对C#/ NHibernate更熟悉。


DetachedCriteria subQuery = DetachedCriteria.forClass(Transaction.class);
subQuery.setProjection(Projections.sum("amount"));
subQuery.add(Expression.eqProperty("userPk", "tOuter.userPk"));

DetachedCriteria outerQuery = DetachedCriteria.forClass(Transaction.class, "tOuter");
outerQuery.setProjection(Projections.projectionList()
    .Add(Projections.sum("amount").as("sumAmount"))
    .Add(Projections.groupProperty("userPk").as("user_pk"));
outerQuery.add(Subqueries.le(50, subQuery));


This code should result in SQL similar to:

此代码应该导致SQL类似于:


SELECT tOuter.userPk as user_pk, sum(tOuter.amount) as sumAmount
FROM transaction tOuter
WHERE 50 <= (SELECT sum(amount) FROM transaction WHERE userPk = tOuter.userPk)
GROUP BY tOuter.userPk

The disadvantage of this approach is that it calculates each of the sums twice, this might have a detrimental effect on performance depending on the amount of data involved - in which case you will want to use an HQL query which does support the HAVING clause.

这种方法的缺点是它会计算两次总和,这可能会对性能产生不利影响,具体取决于所涉及的数据量 - 在这种情况下,您将需要使用支持HAVING子句的HQL查询。

#2


HHH-1700 was marked as a duplicate of HHH-1043, and therefore won't be fixed. You'll find my solution and workaround, as well as other peoples', on HHH-1043.

HHH-1700被标记为HHH-1043的复制品,因此不会被固定。你会在HHH-1043上找到我的解决方案和解决方法,以及其他人。

#1


I don't know of a way for Hibernate/NHibernate to use a subquery in the FROM clause but you can use them in the WHERE clause. Apologies for any Java/Hibernate code mistakes, I am more familiar with C#/NHibernate.

我不知道Hibernate / NHibernate在FROM子句中使用子查询的方法,但您可以在WHERE子句中使用它们。对任何Java / Hibernate代码错误表示歉意,我对C#/ NHibernate更熟悉。


DetachedCriteria subQuery = DetachedCriteria.forClass(Transaction.class);
subQuery.setProjection(Projections.sum("amount"));
subQuery.add(Expression.eqProperty("userPk", "tOuter.userPk"));

DetachedCriteria outerQuery = DetachedCriteria.forClass(Transaction.class, "tOuter");
outerQuery.setProjection(Projections.projectionList()
    .Add(Projections.sum("amount").as("sumAmount"))
    .Add(Projections.groupProperty("userPk").as("user_pk"));
outerQuery.add(Subqueries.le(50, subQuery));


This code should result in SQL similar to:

此代码应该导致SQL类似于:


SELECT tOuter.userPk as user_pk, sum(tOuter.amount) as sumAmount
FROM transaction tOuter
WHERE 50 <= (SELECT sum(amount) FROM transaction WHERE userPk = tOuter.userPk)
GROUP BY tOuter.userPk

The disadvantage of this approach is that it calculates each of the sums twice, this might have a detrimental effect on performance depending on the amount of data involved - in which case you will want to use an HQL query which does support the HAVING clause.

这种方法的缺点是它会计算两次总和,这可能会对性能产生不利影响,具体取决于所涉及的数据量 - 在这种情况下,您将需要使用支持HAVING子句的HQL查询。

#2


HHH-1700 was marked as a duplicate of HHH-1043, and therefore won't be fixed. You'll find my solution and workaround, as well as other peoples', on HHH-1043.

HHH-1700被标记为HHH-1043的复制品,因此不会被固定。你会在HHH-1043上找到我的解决方案和解决方法,以及其他人。

#3