QueryDSL窗口函数

时间:2015-06-12 07:46:33

标签: java jpa querydsl

如何使用窗口函数编写查询并选择QueryDSL中的所有字段? 在文档中有一个这样的例子:

query.from(employee)
.list(SQLExpressions.rowNumber()
    .over()
    .partitionBy(employee.name)
    .orderBy(employee.id));

但我需要生成一个类似的查询:

SELECT * FROM 
  (SELECT employee.name, employee.id, row_number() 
    over(partition BY employee.name
    ORDER BY employee.id)
  FROM employee) AS sub
WHERE row_number = 1

是否可以使用JPAQuery进行此操作?

2 个答案:

答案 0 :(得分:11)

JPAQuery仅支持JPQL的表达性,因此不支持窗口函数,但是分页应该可以使用

query.from(employee).orderBy(employee.id).limit(1)

如果您需要使用窗口函数,并且需要employee.name和employee.id,这应该可以正常工作

NumberExpression<Long> rowNumber = SQLExpressions.rowNumber()
    .over()
    .partitionBy(employee.name)
    .orderBy(employee.id).as("rowNumber");

query.select(employee.name, employee.id)
    .from(SQLExpressions.select(employee.name, employee.id, rowNumber)
                        .from(employee).as(employee))
    .where(Expressions.numberPath(Long.class, "rowNumber").eq(1L))
    .fetch();

答案 1 :(得分:0)

@timo 编写的JPQL(JPA 2.1版本)和JPAQuery(QueryDsl Jpa 4.1.4)不支持窗口函数(rank,row_number)。

但是,你可以重写你的查询,这样就不会使用rank over():

select a.* from employees a
where
(
    select count(*) from employees b
    where 
       a.department = b.department and
       a.salary <= b.salary
) <= 10
order by salary DESC

这是JPAQuery支持的,它可能是这样的。

final BooleanBuilder rankFilterBuilder = 
    new BooleanBuilder(employee.department.eq(employee2.department));
rankFilterBuilder.and(employee.salary.loe(employee2.salary));

query.from(employee)
.where(JPAExpressions.selectFrom(employee2)
            .where(rankFilterBuilder)
            .select(employee2.count())
            .loe(10))
.orderBy(employee.salary);