【问题标题】:HQL query for entity with max value具有最大值的实体的 HQL 查询
【发布时间】:2011-05-28 17:04:50
【问题描述】:

我有一个看起来像这样的 Hibernate 实体(为简洁起见,省略了访问器):

@Entity
@Table(name="FeatureList_Version")
@SecondaryTable(name="FeatureList",
    pkJoinColumns=@PrimaryKeyJoinColumn(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 的最高版本号记录的关键。如果我在 select 中添加 f.key 它将不起作用,因为它不在 group by 或聚合中,如果我将它放在 group by 整个事情停止工作,它只是给我每个版本作为一个单独的实体。

那么,有人可以帮忙吗?

【问题讨论】:

    标签: java hibernate hql


    【解决方案1】:

    此查询的简单版本如下所示(假设 (name, version) 对是唯一的):

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

    【讨论】:

    • 确实,它更简单更高效。实际上,查看原始查询中的group by 让我一直在思考这个问题。我会考虑这一点,在重组我提出的查询方面更进一步。 +1
    【解决方案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           
    

    注意:这次尝试使用 MySQL。它的工作。我很确定 MS SQL Server 也有 IN (...) 运算符。你只需要在 Hibernate 中使用session.createNativeQuery()


    编辑工作于axtavt's answer

    我们发现这可以很简单,

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

    现在尝试使用Hibernate Criteria API

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

    【讨论】:

    • 非常好。 +1 标准实施
    【解决方案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 暗示她/他只需要 1 行,但上述查询适用于不同数量的结果)

    以下似乎要快得多:

    FROM FeatureList ORDER BY version DESC LIMIT 1;
    

    我对表中有 700,000 条记录的类似查询进行试验,前者大约需要 0.19 秒,后者大约需要 0.05 秒。

    【讨论】:

    【解决方案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 查询,不确定是否有任何其他数据库。


    有一个问题,nameversion 这对是独一无二的吗?如果是,那么很好,否则如果这对不是唯一的,你认为如何选择一个密钥?假设原始查询中的一条记录是,

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

    并假设有 3 个keys 具有相同的对。现在回答,应该为该记录分配哪个键?我希望你明白我的意思。

    【讨论】:

    • 不,这不起作用,因为您不能将两个值与返回的子查询进行比较。 Hibernate 在 fl.name 之后返回一个抱怨 , 的 SQLGrammarException
    • @Rob:更新了我的答案以供进一步讨论。
    • 不幸的是,它不是 MSSQL 中的有效查询,它需要针对它运行。名称和版本一起是唯一的,但是如果您将密钥添加到分组中,您将获得密钥、名称和版本的每个组合,这意味着每个不同的版本,而不仅仅是最新的(具有最高版本号)
    • @Rob:不,你得到了keyname 的组合,version 不是group by 的一部分。如果这对是唯一的,那么我提出的第二个查询将返回相同数量的记录。试试看,然后告诉我。
    • 哦,对了。不,密钥和名称对不是唯一的。 key 是 name 和 version 唯一配对的 key,因此单个 name 的 key 与 version 一样多。
    【解决方案5】:

    用 distinct + order by 代替 group by 怎么样?

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-12-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-01-09
      相关资源
      最近更新 更多