Grails / GORM / HQL:消除FROM部分中的内部查询

时间:2011-07-27 13:55:51

标签: grails hql gorm

我有一张与此类似的表“表”:

id     user_id      owner_id      due_date
------+------------+-------------+--------------------------
1     | 1          | 1           | 2011-07-26 12:28:50
2     | 1          | 1           | 2011-07-26 15:32:11
3     | 1          | 1           | 2011-07-27 08:11:58
4     | 2          | 1           | 2011-07-26 15:19:44
5     | 2          | 1           | 2011-07-23 12:00:50

如您所见,由FK user_id标识的用户可以拥有多个具有不同due_date的条目。

我想获取按user_id分组的所有最新Table个实体。

在普通的MySQL中,它看起来像这样:

SELECT * FROM (
    SELECT * FROM TABLE
      WHERE owner_id = xxx
      ORDER BY due_date DESC
  ) AS sorted
GROUP BY user_id

我首先选择ORDER BY,然后应用GROUP BY(遗憾的是,所有的SELECT都不起作用。请参阅此处http://www.cafewebmaster.com/mysql-order-sort-group)。

现在我想将其实现为HQL(使用Grails)。问题是HQL不支持FROM部分中的内部SELECT,因此以下方法不起作用:

def findMostRecentPerUser( Owner owner ) {
    def result = Table.executeQuery("""
                from Table as t1
                where t1.id in (
                    select sorted.id from (select * from Table as t2 where t2.owner_id = ${owner.id} order by t2.due_date desc) as sorted group by sorted.user_id
            )
        """)
    return result
}

另一种方式是Criteria,但我不知道如何以这种方式实现它。

有人能指出我正确的方向吗?非常感谢您的帮助。

3 个答案:

答案 0 :(得分:0)

为什么不将MySql从其中删除,只返回结果并使用Comparator进行排序。这样,无论数据库如何实现排序,您都可以进行排序。

List<Table> results = query();
Collections.sort(results, YourCustomComparator.getInstance());

这样做也会减少数据库的负担,因为它变成了一个简单的查询而没有按顺序排序。

请参阅收藏集文档here

答案 1 :(得分:0)

我不确定您的意图是否可行(我甚至不确定是否能够使用原始SQL执行此操作)。

您想要使用Group By语句(在我的理解中)与聚合函数一起使用时只有意义,但您没有使用聚合函数。我假设您的目标是获得如下所示的数据结构:[user_id_1: [t1, t5, t2], user_id_2: [t3, t4, t8]...](其中tX是Table中的实例)是正确的吗?

如果是这种情况,我认为您只需要获得您关心的实例集并自行组织:

def findMostRecentPerUser( Owner owner ) {
  def someDate = new Date() - 5 // 5 Days ago
  def result = [:].withDefault{[]}
  Table.withCriteria {
    eq('owner.id', owner.id)
    gt('due_date', someDate)
    order('due_date', 'desc')
  }.each{result[it.user.id] << it}
  return result
}

但是,正如您所看到的,这只会为您提供在某个日期之后发生的实例(或者,删除gt语句,它会为您提供所有实例,这可能不是您想要的实例。您可以使用distinct('user.id')

将其限制为每个用户的单个最新实例

但是,如果您想要为每个用户提供5个最新实例,我认为您将无法为每个用户执行查询(当然,将结果集限制为5)。如果有人有一个解决方案,我很有兴趣看到这个案例的解决方案。

答案 2 :(得分:0)

这种方式应该有效。改进升值。

def findMostRecentPerUser( Owner owner ) {
    // Inner query sorts maximum due_date per user
    // Outer query fetches all Table entries with this due_date
    def result = Table.executeQuery("""
            from Table as t1
            where t1.due_date in (
                select max(t2.due_date) from Table as t2 where t2.owner = :owner group by t2.user
            )
        """,
        [ owner: owner ] )
    return result
}