Подтвердить что ты не робот

Запрос HQL для объекта с максимальным значением

У меня есть объект Hibernate, который выглядит следующим образом (аксессоры опущены для краткости):

@Entity
@Table(name="FeatureList_Version")
@SecondaryTable(name="FeatureList",
    [email protected](name="FeatureList_Key"))
public class FeatureList implements Serializable {

    @Id
    @Column(name="FeatureList_Version_Key")
    private String key;

    @Column(name="Name",table="FeatureList")
    private String name;

    @Column(name="VERSION")
    private Integer version;

}

Я хочу создать HQL-запрос, который извлекает самую последнюю версию FeatureList. Следующие виды запросов:

Select f.name, max(f.version) from FeatureList f group by f.name

Проблема заключается в том, что не будет заполнено поле ключа, в котором мне нужно будет содержать ключ записи с наивысшим номером версии для данного FeatureList. Если я добавлю f.key в select, это не сработает, потому что это не в группе или в агрегате, и если я поместил ее в группу, все перестанет работать, и она просто дает мне каждую версию как отдельный объект.

Итак, может ли кто-нибудь помочь?

4b9b3361

Ответ 1

Прямая версия этого запроса выглядит так (при условии, что пары (name, version) уникальны):

select f from FeatureList f 
where f.version = 
     (select max(ff.version) from FeatureList ff where ff.name = f.name)

Ответ 2

Я сделал сценарий здесь,


Таблица

key          name                 version         
----------- -------------------- ----------- 
1           adeel                1           
2           adeel                2           
3           adeel                3           
4           ahmad                1           
5           ahmad                2           
6           ahmad                3           
7           ahmad                4           
8           ansari               1           
9           ansari               2           
10          ansari               3           

Результат с использованием исходного запроса

>> select f.name, max(f.version) from FeatureList f group by f.name

name                 max(f.version) 
-------------------- ------------ 
adeel                3            
ahmad                4            
ansari               3            

Результат с использованием желаемого запроса

>> select fl.* from FeatureList fl 
   where (fl.name, fl.version) in (select f.name, max(f.version) 
                                           from FeatureList f group by f.name);

key          name                 max(fl.version)  
----------- -------------------- ----------- 
3           adeel                3           
7           ahmad                4           
10          ansari               3           

NB: на этот раз пробовал использовать MySQL. Работает. Я уверен, что MS SQL Server также имеет оператор IN (...). Вам просто нужно использовать session.createNativeQuery() в спящем режиме.


Отредактировано для работы над ответом axtavt

Как мы выяснили, это можно сделать так просто, как

select f from FeatureList f 
where f.version = 
     (select max(ff.version) from FeatureList ff where ff.name = f.name)

Теперь попробуйте сделать то же самое, используя API-интерфейс Hibernate Criteria,

DetachedCriteria versions = DetachedCriteria.forClass(FeatureList.class, "f")
    .setProjection( Property.forName("f.version").max())
    .add(Property.forName("f.name").eqProperty("fl.name"));

session.createCriteria(FeatureList.class, "fl")
    .add( Property.forName("fl.version").eq(versions) )
    .list();

Ответ 3

Старый вопрос, но я думал, что предоставил бы мой опыт и для будущих пользователей:

select f from FeatureList f where f.version = 
 (select max(ff.version) from FeatureList ff where ff.name = f.name);

Это отлично работает, но если выполнено следующее:

  • MySql v5.5 w/движок InnoDB
  • Вы точно знаете, сколько строк результата вы хотите (OC подразумевает, что он/она хочет ровно одну строку, но указанный выше запрос будет работать для различного количества результатов)

выглядит значительно быстрее:

FROM FeatureList ORDER BY version DESC LIMIT 1;

Мои испытания по аналогичному запросу с 700 000 записей в таблице занимают около 0.19s для прежней версии и 0.05s для последнего.

Ответ 4

Как насчет этого,

from FeatureList fl where (fl.name, fl.version) in (
               select f.name, max(f.version) from FeatureList f group by f.name)

Примечание. Попробуйте использовать createNativeQuery(), его действительный запрос Oracle, не уверен в какой-либо другой базе данных.


Один вопрос, является ли пара, name и version уникальной? Если да, то это хорошо, иначе, если пара не уникальна, как вы думаете, как будет выбран ключ? Предположим, что одна из записей из исходного запроса:

f.name         max(f.version)
------         --------------
Django         1.2

и предположим, что существует 3 key, имеющих одну и ту же пару. Теперь ответьте, какой ключ должен быть присвоен этой записи? Надеюсь, вы поняли мою точку зрения.

Ответ 5

Как насчет использования отдельного + порядка вместо группы?

select f.id, distinct(f.name), f.version from FeatureList f order by f.version desc