2011-07-27 46 views
0

我有一個表「表」與此類似:Grails的/格姆/ HQL:消除內部查詢的FROM部分

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不支持在內部SELECT的FROM部分,所以下面的方法將不起作用:

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 
} 

另一種方式是一個標準,但我不知道如何實現它的方式。

有人可以指引我進入正確的方向嗎?非常感謝您的幫助。

+0

你想返回一組日期? –

+0

我覺得我很困惑。爲什麼你需要一個子查詢?只是按日期排序嗎? –

+0

我想選擇整行,即完整的「表」實體以在Grails中進一步使用。我在原來的問題中澄清了這一點。子查詢是必需的,因爲一個簡單的'GROUP BY user_id ORDER BY due_date'不會導致正確的結果,請參閱此處以獲取類似的問題描述:http://www.cafewebmaster.com/mysql-order-sort-group – void

回答

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 
} 
+0

顯示工作正常,謝謝! – void

0

爲什麼不直接離開MySql,只需要返回結果並使用Comparator進行排序。無論數據庫如何實現它,這種方式您都可以享受排序。

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

這樣做也會減少數據庫的負載,因爲它會變成一個簡單的查詢,而無需排序。

查看Collections文檔here

+0

謝謝爲你的答覆,邁克爾。由於結果集可能會變得很大,我不想加載所有記錄只是爲了對它們進行排序,我寧願在查詢中處理這些。此外,HQL查詢還應抽象數據庫實現細節。 – void

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)。如果有人有這種情況,我很感興趣看到這種情況的解決方案。

+0

你的假設是正確的,除了我只對每個用戶的最近一行感興趣。我已經嘗試應用一個獨特的,但這基本上有問題作爲上面的GROUP BY問題 - 以下代碼返回錯誤的行,因爲獨特似乎首先應用。 DEF結果= {Table.withCriteria \t當量( 「所有者」,擁有者) \t突起{ \t \t不同( 「用戶」) \t} \t順序( 「DUE_DATE」, 「降序」) } – void

+0

阿,所以會。嗯...我能想到的唯一的其他事情將涉及到一個重構:爲用戶添加一個字段給mostRecentTable,然後你可以加入該屬性來以正確的方式限制結果(這對於需要更新用戶對象每當一個關聯的Table對象被創建時 - 假設你可以用另一個關聯表來完成)。我沒有任何其他想法嚴格執行您的查詢。祝你好運! – Kyle