【问题标题】:Calculating rank on an aggregate column in a Hibernate SQLProjection计算 Hibernate SQLProjection 中聚合列的排名
【发布时间】:2011-11-25 22:30:29
【问题描述】:

我正在尝试编写一个查询来根据聚合列计算排名列。该查询是作为 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),则查询有效(但显然无法正确计算排名)。


在此 sqlProjection 查询中使用 {alias} 似乎有问题 - 可能与嵌套子查询有关 - 谁能帮忙?

谢谢。

【问题讨论】:

    标签: hibernate hql criteria aggregation hibernate-criteria


    【解决方案1】:

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

    • 在 SQL 中编写此查询并将其作为native query 执行
    • 这样写

      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,因为条件应该在第一次聚合之后应用。

    【讨论】:

    • 谢谢,关于 HQL 查询选择子句 (+1) 中不允许子选择,您的回答是正确的,但我意识到我在问题中犯了一个错误 - 代码实际上不是 HQL,它是SQLProjection 作为 Criteria 查询的一部分,本机 SQL 也是如此。我已经澄清并纠正了这个问题,请参阅编辑。
    • @KLibby:如果是这样,完整的条件查询看起来如何?
    • 我现在已经为我构建的 Hibernate Criteria 添加了完整的代码。
    • @KLibby:group by 在您的标准中在哪里?看起来你在没有它的情况下申请了max
    • 我认为它快到了,但查询仍然有错误 - 我已经进一步编辑了我的问题,以包括您的解决方案的结果和 Hibernate 生成的 SQL。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-05-30
    • 2014-02-07
    • 1970-01-01
    • 1970-01-01
    • 2015-08-11
    • 1970-01-01
    • 2018-01-14
    相关资源
    最近更新 更多