2016-02-02 2 views
1

У меня есть SQL заявление что-то вроде этого:JPA CriteriaBuilder для присоединиться к подзапрос

SELECT * FROM person inner join (select max(validityId) as maxID from person group by personId) maxID on maxID.maxID = person.validityid; 

Так дайте мне "отчетливый" строку для PersonId:

Если у меня есть таблица вроде этого:

| personID | validitID | value | 
------------------------------------------- 
| 1  | 10  | 400  | 
| 1  | 11  | 500  | 
| 1  | 12  | 600  | 
| 2  | 13  | 700  | 
| 2  | 14  | 800  | 
| 2  | 15  | 900  | 
| 4  | 16  | 1000 | 

он вернется бы

| personID | validitID | value | 
------------------------------------------- 
| 1  | 12  | 600  | 
| 2  | 15  | 900  | 
| 4  | 16  | 1000 | 

Теперь я пытаюсь сделать это с помощью JPA CriteriaBuilder.

Моя первая мысль была суб-запрос:

final CriteriaBuilder cb = this.em.getCriteriaBuilder(); 
final CriteriaQuery<Person> cq = cb.createQuery(Person.class); 
final Root<Person> root = cq.from(Person.class); 
cq.select(root); 

final Subquery<Long> subquery = cq.subquery(Long.class); 
final Root<Person> validityIDSQ = subquery.from(Person.class); 
subquery.select(validityIDSQ.get(Person_.validityId)); 
subquery.groupBy(validityIDSQ.get(Person_.personId)); 

cb.where(cb.in(root.get(Person_.validityId)).value(subquery)); 

Но это производят ошибку

ERROR: column "person1_.validityid" must appear in the GROUP BY clause or be used in an aggregate function 

Как это право?

Марко

+1

В подзапросе вы не используете функцию агрегирования. Это не проблема JPA, даже SQL сбой для 'select validityId из группы X personId'. Попробуйте 'subquery.select (cb.sum (validityIDSQ.get (Person_.validityId)))' – SJuan76

+0

Какую базу данных вы используете? –

ответ

3

Я думаю, что решение проще, чем кажется. Вы забыли включить cb.max() в подзапрос CriteriaBuilder. Следующий код выполняет запрос, который вы ищете.

final CriteriaBuilder cb = entityManager.getCriteriaBuilder(); 
final CriteriaQuery<Person> cq = cb.createQuery(Person.class); 
final Root<Person> root = cq.from(Person.class); 
cq.select(root); 

final Subquery<Integer> subquery = cq.subquery(Integer.class); 
final Root<Person> validityIDSQ = subquery.from(Person.class); 
subquery.select(cb.max(validityIDSQ.get(Person_.validityID))); 
subquery.groupBy(validityIDSQ.get(Person_.personID)); 

cq.where(cb.in(root.get(Person_.validityID)).value(subquery)); 

Этот код создаст следующий запрос:

select 
    person0_.id as id1_0_, 
    person0_.personID as personID2_0_, 
    person0_.validityID as validity3_0_, 
    person0_.value as value4_0_ 
from 
    person person0_ 
where 
    person0_.validityID in (
      select 
       max(person1_.validityID) 
      from 
       person person1_ 
      group by 
       person1_.personID) 

Я думаю, что вы используете Postgres. Без cd.max() он генерирует ошибку, которую вы указали, потому что вы используете GroupBy без использования агрегатной функции. Я тестировал его на Postgres и MySQL. Бегает как обаяние на обоих.

Смежные вопросы