2009-01-21 21 views
10

He escrito una consulta usando Hibernate Criteria API para obtener una suma de un valor particular, ahora necesito poder restringir el resultado a filas donde esa suma es mayor o igual a un valor particular.Hibernate Criterios API - cláusula HAVING work arounds

Normalmente usaría una cláusula HAVING en mi SQL para hacer esto, pero la API de Criteria no parece ser compatible con eso en este momento.

En SQL cruda esto es lo que necesito que haga:

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

Una solución alternativa que pensé es usar una subconsulta en la cláusula que agarra este valor de la suma y el uso de una consulta externa para restringirlo usando una cláusula WHERE.

Así, en SQL prima que se verá algo como:

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

Puede alguien me punto en la dirección correcta en cuanto a cómo podría escribir esto usando la API Criteria, o cualquier otra sugerencia/soluciones temporales que puede usar para resolver el problema HAVING?

Este es el código de la API Criterios que tengo para el ejemplo anterior

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"))); 

Gracias!

Respuesta

8

No conozco la posibilidad de que Hibernate/NHibernate use una subconsulta en la cláusula FROM, pero puede usarlas en la cláusula WHERE. Disculpas por cualquier error de código de Java/Hibernate, estoy más familiarizado con 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)); 

 

Este código debe resultar en SQL similar a:

 

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 
 

La desventaja de este enfoque es que calcula cada una de las sumas dos veces, esto podría tener un efecto perjudicial sobre el rendimiento en función de la cantidad de los datos involucrados, en cuyo caso querrá usar una consulta HQL que admita la cláusula HAVING.

2

HHH-1700 fue marcado como duplicado de HHH-1043, y por lo tanto no será fijo. Encontrará mi solución y solución, así como la de otras personas, en el HHH-1043.

+0

esto fue hace 7 años y todavía no está parcheado en hibernate, tengo que aplicar el parche para la versión 4.3.6 o posterior, pero el código había sido cambiado tanto que no estoy seguro de cómo hacerlo. ¿Alguien tiene este parche actualizado? –

Cuestiones relacionadas