3

我正在尝试编写一个查询来根据聚合列计算排名列。该查询是作为 Hibernate Criteria 查询一部分的 SQLProjection。这是我尝试过的:

String sqlProjection = 
    "(select count(*) from IPTStatistic stat2 where 
               max(s.powerRestarts) > max({alias}.powerRestarts)) as rank)";

ProjectionList list = Projections.projectionList();

list.add(Projections.sqlProjection(sqlRankQuery, new String[]{"rank"}, new Type[]{new IntegerType()})));
list.add(Property.forName("managedObjectName").group());
list.add(Projections.max("powerRestarts").as("maxRestarts"));

Criteria crit = hibernateSessionHelper.getSessionFactory().getCurrentSession().createCriteria(IPTStatistic.class);
crit.setProjection(projection);

crit.list();

当我在 SQL 投影中使用非聚合列时,子选择起作用并且我得到了预期的结果,只有在我引入max()错误时才会发生错误。

这会引发一个相当不具体org.hibernate.exception.GenericJDBCException的消息“ Could not execute query”。

日志显示:

WARN   logExceptions, SQL Error: -458, SQLState: S1000
ERROR  logExceptions, java.lang.NullPointerException java.lang.NullPointerException

我无法从上述错误消息中自己查明查询中的问题,谁能给我一些关于如何更正我的查询的指示?


更新:

我现在根据下面的 axtavt 的回答使用以下 sqlProjection:

String sqlProjection = "(select count(*) from " +
    "(select name from IPTStatistic s group by s.name " + 
    "    having max(s.powerRestarts) > max({alias}.powerRestarts)) " +
    "as r) as rank"

Hibernate生成的SQL是:

select (select count(*) from (select iptManagedObjectName from IPTStatistic s group by s.iptManagedObjectName having max(s.powerRestarts) > max(this_.powerRestarts)) as r) as rank, this_.iptManagedObjectName as y1_, from IPTStatistic this_ 

我现在收到错误:

WARN   logExceptions, SQL Error: -5581, SQLState: 42581
ERROR  logExceptions, unexpected token: SELECT

如果我删除max({alias}.powerRestarts)并用常量或替换它max(s.powerRestarts),则查询有效(但显然没有正确计算排名)。


{alias}在这个查询中使用似乎有问题sqlProjection- 可能与嵌套子查询有关 - 任何人都可以帮忙吗?

谢谢你。

4

1 回答 1

2

HQL 不支持select列表中的子查询,因此您有两种选择:

  • 用 SQL 编写此查询并将其作为本机查询执行
  • 写类似

    select max(stat.powerRestarts), stat.managedObjectName 
    from IPTStatistic stat 
    group by stat.managedObjectName
    order by max(stat.powerRestarts) desc
    

    然后可以从行号以编程方式推导出排名

更新:

这里重要的一点是,您需要执行两个聚合 (maxcount) 才能计算排名,因此您需要两个查询来执行此操作:

String sqlProjection = 
    "(select count(*) from " +
    "(select name from IPTStatistic s group by s.name " + 
    "    having max(s.powerRestarts) > max({alias}.powerRestarts)) " +
    "as r) as rank";

还要注意使用having代替where,因为条件应该在第一次聚合之后应用。

于 2011-09-27T11:32:36.267 回答