我有一张与此类似的表“表”:
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,但我不知道如何以这种方式实现它。
有人能指出我正确的方向吗?非常感谢您的帮助。
答案 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
}