Grails / GORM / HQL: устранение внутреннего запроса в части FROM - PullRequest
0 голосов
/ 27 июля 2011

У меня есть таблица «Таблица», похожая на эту:

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.

Я хотел бы получить все последние Table сущности, сгруппированные по user_id.

В простом 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
}

Другой способ - это Критерии, но я не знаю, как это реализовать.

Может ли кто-нибудь указать мне правильное направление? Ваша помощь очень ценится.

Ответы [ 3 ]

0 голосов
/ 27 июля 2011

Я не уверен, что то, что вы намереваетесь, возможно (я даже не уверен, что вы должны быть в состоянии сделать это с необработанным 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 голосов
/ 02 августа 2011

Этот способ должен работать.Улучшения приветствуются.

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 голосов
/ 27 июля 2011

Почему бы просто не оставить MySql вне этого и просто получить результаты обратно и использовать Comparator для сортировки.Таким образом, вы можете гарантировать одинаковую сортировку независимо от того, как ее реализует база данных.

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

Это также уменьшит нагрузку на вашу базу данных, поскольку она превращается в простой запрос без заказа.1006 *

См. Коллекцию документов здесь .

...