计算 Hibernate SQLProjection 中聚合列的排名

发布于 2024-12-06 14:22:52 字数 2123 浏览 0 评论 0原文

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

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,并带有消息“无法执行查询”。

日志显示:

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} 似乎存在问题 - 可能与嵌套子查询有关 - 有人可以帮忙吗?

谢谢。

I am trying to write a query to calculate a rank column based upon an aggregate column. The query is an SQLProjection as part of a Hibernate Criteria query. Here is what I have tried:

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

When I use a non-aggregate column in the SQL projection, the subselect works and I get the expected results, it is only once I introduce the max() that the error occurs.

This throws a fairly non-specific org.hibernate.exception.GenericJDBCException with message "Could not execute query".

The log shows:

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

I can't pinpoint the problem in the query myself from the above error messages, can anyone give me some pointers on how to correct my query?


UPDATE:

I am now using the following sqlProjection as per axtavt's answer below:

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"

The SQL generated by Hibernate is:

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_ 

I am now getting the error:

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

If I remove max({alias}.powerRestarts) and replace it with either a constant or max(s.powerRestarts), then the query works (but obviously does not calculate the rank correctly).


There seems to be a problem using the {alias} in this sqlProjection query - possibly something to do with the nested subqueries - can anyone help?

Thankyou.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

电影里的梦 2024-12-13 14:22:52

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

  • 用 SQL 编写此查询并将其作为 原生查询
  • 写一些类似的内容

    选择 max(stat.powerRestarts), stat.managementObjectName 
    来自IPTStatistic统计 
    按 stat.managementObjectName 分组
    按 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 doesn't support subqueries in select list, thus you have two options:

  • Write this query in SQL and execute it as a native query
  • Write something like

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

    then rank can be deduced programmatically from a row number

UPDATE:

An important point here is that you need to perform two aggregations (max and count) in order to calculate a rank, so that you need two queries to do it:

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

Also note the use of having instead of where, since condition should be applied after the first aggregation.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文