Grails/GORM/HQL:消除 FROM 部分中的内部查询
我有一个与此类似的表“Table”:
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,但我不知道如何以这种方式实现它。
有人能指出我正确的方向吗?非常感谢您的帮助。
I have a table "Table" similar to this one:
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
As you can see, a user identified by FK user_id
can have multiple entries with different due_date
.
I would like to fetch all most recent Table
entities grouped by user_id.
In plain MySQL, it could look like this:
SELECT * FROM (
SELECT * FROM TABLE
WHERE owner_id = xxx
ORDER BY due_date DESC
) AS sorted
GROUP BY user_id
I would first select with ORDER BY, then apply a GROUP BY (all in one SELECT doesn't work, unfortunately. see e.g. here http://www.cafewebmaster.com/mysql-order-sort-group).
Now I would like to implement this as HQL (with Grails). The problem is that HQL does not support inner SELECT's in the FROM part, so the following approach won't work:
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
}
Another way would be a Criteria but I've no idea how to implement it that way.
Could someone point me into the right direction? Your help is greatly appreciated.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
这种方法应该有效。改进表示赞赏。
This way should work. Improvements appreciated.
为什么不直接将 MySql 排除在外,只获取结果并使用 比较器进行排序。这样,无论数据库如何实现,您都可以保证排序是相同的。
这样做还会减少数据库的负载,因为它变成了一个没有 order by 的简单查询。
请参阅此处的集合文档。
Why not just leave MySql out of it and just get the results back and use a Comparator to sort. This way you can garentee sort will be the same regardless of how a database implements it.
Doing this will also decrease the load on your database because it turns into a simple query without an order by.
See the Collections doc here.
我不确定您的意图是否可行(我什至不确定您应该能够使用原始 SQL 来完成它)。
您想要使用
Group By
语句,该语句(根据我的理解)仅在与聚合函数结合使用时才有意义,但您没有使用聚合函数。我假设您的目标是获得如下所示的数据结构:[user_id_1: [t1, t5, t2], user_id_2: [t3, t4, t8]...]
(其中 tX 是Table
中的实例)是否正确?如果是这种情况,我认为您只需要获取您关心的一组实例并自行组织它们:
但是,正如您所看到的,这只会为您提供在某个日期之后发生的实例(或者删除
gt
语句,它为您提供所有实例,这可能不是您想要的)。您可以使用distinct('user.id')
将其限制为每个用户的最近一个实例,但是如果您想要每个用户的 5 个最近实例,我认为您会为每个用户执行查询(当然,将结果集限制为 5 个)。如果有人有这个案例的解决方案,我非常有兴趣找到解决方案。
I'm not sure that what you're intending is possible (I'm not even sure you should be able to do it with raw SQL).
You want to use a
Group By
statement which (in my understanding) only has meaning when used in conjunction with aggregate functions, but you're not using an aggregate function. I assume your goal is to get a data structure looking like this:[user_id_1: [t1, t5, t2], user_id_2: [t3, t4, t8]...]
(where tX is an instance out ofTable
) is that correct?If that's the case I think you just need to get the set of instances you care about back and organize them yourself:
However, as you can see, this only gives you instances that occurred after some date (or, removing the
gt
statement, it gives you all instances, which is probably not what you want). You could restrict it down to the single most recent instance per user by usingdistinct('user.id')
But if you wanted, say, the 5 most recent instances for each user I think you'd be stuck doing a query for each user (and limiting the result set to 5, of course). I'm very interested in seeing a solution for this case if someone has one.