выбрать наибольший элемент для группы в querydsl - PullRequest
2 голосов
/ 11 октября 2019

У меня есть таблица sql, которая выглядит примерно так:

+-----+------+-------+
|  id | type | value |
+-----+------+-------+
|  1  |   X  |   20  |
|  2  |   X  |   30  |
|  3  |   Y  |  200  |
|  4  |   Y  |  500  |
|  5  |   Y  |  300  |
|  6  |   Z  |    5  |
+-----+------+-------+

Для каждого типа я хочу получить строку с максимальным значением. Это мой ожидаемый результат:

+-----+------+
|  id | type |
+-----+------+
|  2  |   X  | <-- had value = 30
|  4  |   Y  | <-- had value = 500
|  6  |   Z  | <-- had value = 5
+-----+------+

В SQL это можно выразить следующим образом (учитывая, что для каждого типа нет двух записей с одинаковым значением, которое я могу исключить):

select t1.id, t1.type from T t1
inner join (
  select t2.type, max(t2.value) as max_value from T t2
  group by t2.type
) on t1.type = t2.type
  and t1.value = max_value

Однако я не могу найти способ выразить то же самое с помощью QueryDSL (версия 4). Я попробовал это:

final JPQLQuery<Tuple> subquery = JPAExpressions
    .from(q2)
    .select(q2.type, q2.value.max())
    .groupBy(q2.type);
final JPQLQuery<Tuple> query = JPAExpressions
    .from(q1)
    .select(q1.id, q1.type)
    .from(q1)
    .innerJoin(subquery) // <-- not allowed
    .on(q1.type.eq(q2.type), q1.value.eq(q2.value.max()));

Но innerJoin() (и другие методы соединения) принимают только выражение в качестве параметра, а не другой запрос. То же самое касается from().

1 Ответ

0 голосов
/ 14 октября 2019

Подзапрос может быть помещен в предложение where внешнего запроса в виде exists -выражения:

final JPQLQuery<Tuple> subquery = JPAExpressions
    .from(q2)
    .select(q2.type, q2.value.max())
    .groupBy(q2.type);
final JPQLQuery<Tuple> query = JPAExpressions
    .from(q1)
    .select(q1.id, q1.type)
    .from(q1)
    .where(subquery
        .having(q1.type.eq(q2.type), q1.value.eq(q2.value.max()))
        .exists());

Обратите внимание, что этот запрос может быть весьма неэффективным.

...