Вычисление ранга для статистического столбца в Hibernate SQLProjection - PullRequest
3 голосов
/ 27 сентября 2011

Я пытаюсь написать запрос для расчета столбца ранга на основе совокупного столбца.Запрос является 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 с сообщением "Could not execute query".

В журнале показывается:

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

Я не могу точно определить проблему в запросе из приведенных выше сообщений об ошибках. Может ли кто-нибудь дать мне несколько советов о том, как исправить мой запрос?


ОБНОВЛЕНИЕ:

Я сейчас использую следующий sqlProjection в соответствии с ответом axtavt ниже:

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"

SQL, сгенерированный Hibernate:

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 - возможно, что-то связанное с вложенными подзапросами - может кто-нибудь помочь?

Спасибо.

1 Ответ

2 голосов
/ 27 сентября 2011

HQL не поддерживает подзапросы в списке select, поэтому у вас есть два варианта:

  • Написать этот запрос в SQL и выполнить его как собственный запрос
  • Напишите что-то вроде

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

    , тогда ранг может быть выведен программно из номера строки

ОБНОВЛЕНИЕ:

Важным моментом здесь является то, что вам нужно выполнить две агрегации (max и count), чтобы рассчитать ранг, поэтому для этого вам понадобится два запроса:

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, поскольку условие должно применяться после первой агрегации.

...