【问题标题】:QueryDSL Window functionsQueryDSL 窗口函数
【发布时间】:2015-08-28 03:47:37
【问题描述】:

如何使用窗口函数编写查询并选择 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 可以做到吗?

【问题讨论】:

    标签: java jpa querydsl


    【解决方案1】:

    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();
    

    【讨论】:

    • 用 SQLQuery 怎么办?
    • 对于 SQLQuery,最好这样做,因为限制/偏移处理在内部映射到 SQL 引擎提供的分页功能。
    • 好的,谢谢。实际上在我的代码中我需要排名而不是行号,所以限制不起作用。有没有办法像我发布的那样生成查询?
    • 我也在寻找完全相同的功能,QueryDSL 页面中提供的示例并不是很有帮助。 :(
    • 使用 JPAQuery 我收到类似“JPAQueryBase> 类型中的方法 from(EntityPath>) 不适用于参数 (SimpleExpression)”的错误对于这个实现。有什么工作场所吗?
    【解决方案2】:

    @timo 所写,JPQL(JPA 2.1 版本)不支持窗口函数(rank、row_number),因此 JPAQuery(QueryDsl Jpa 4.1.4)不支持。

    但是,您可以重写您的查询,以便不使用 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);
    

    【讨论】:

      猜你喜欢
      • 2014-05-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-12-15
      • 2015-10-12
      • 2016-04-25
      • 2021-09-13
      相关资源
      最近更新 更多