【问题标题】:How to implement this SQL using CriteriaBuilder to build a Predicate?如何使用 CriteriaBuilder 实现此 SQL 来构建谓词?
【发布时间】:2021-02-06 00:26:46
【问题描述】:

我使用Specifications 使用CriteriaBuilder 过滤从我的JpaRepository 使用findAll() 调用的数据,但现在我在SQL 中有一个更复杂的查询,我需要在其中生成一个Predicate我的规范。

SQL 查询是:

SELECT a.*
    FROM A a
LEFT JOIN (SELECT e.a_id, sum(e.amount) AS matched_total
    FROM E e
GROUP BY e.a_id
HAVING e.a_id IS NOT NULL) AS sub ON sub.a_id = a.id
WHERE coalesce(matched_total, 0) = a.amount;

实体 E 链接到 A:

+--------+
| id     |
| amount |
| a_id   |
+--------+

实体 A:

+--------+
| id     |
| amount |
+--------+

(或者也许有一种方法可以将其编写为 HQL 并以某种方式使用它来构建Predicate?)

补充说明:

  1. E 和 A 之间存在一对多的关系,因此 A 中的多行可以与 E 中的单行相关联。
  2. E 中的 a_id 也可以为空,因此 A 中的某些行可能与 E 中的行无关 - 我们需要忽略这些。
  3. 最终,我们希望找到 A 中与 E 中的单个行相关联的所有行,但仅在 A 中的行的 amounts 与 E 中的单个 amount 行相加时 - 这就是为什么我们计算matched_total

【问题讨论】:

    标签: sql hibernate jpa hibernate-criteria criteriaquery


    【解决方案1】:

    除非我遗漏了一些明显的东西,否则查询不等同于以下内容吗?

    SELECT *
    FROM A a
    WHERE a.amount > (
        SELECT SUM(e.amount)
        FROM E e
        WHERE e.a_id = a.id
    )
    

    上面的查询很容易转换为 Criteria API,类似于:

    Root<A> a = cq.from(A.class);
    Subquery<Integer> sum = cq.subquery(Integer.class);
    Root<E> e = sum.from(E.class);
    sum.select(cb.sum(e.get(E_.amount));
    sum.where(cb.equal(e.join(E_.a), a);
    
    cq.where(cb.greaterThan(a.get(A_.amount), sum);
    
    

    【讨论】:

    • 我在上面添加了一些注释,因为我意识到缺少一些重要信息。另请注意,我已在最后的 WHERE 子句中将原始查询更改为 =。我们想忽略加起来不等于matched_totals 的行。
    • 我还是看不出区别。当然,E 中 a_id 为 null 的行不包括在内 - 这就是 WHERE e.a_id = a.id 子句的用途。您能否提供一个您认为查询返回不同结果的示例? (假设&gt; 替换为=
    • 很抱歉延迟回复这个问题 - 我已经休息了几天,无法对此进行测试。有没有办法在不使用 Metamodel API 的情况下做到这一点?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-04-01
    • 1970-01-01
    • 1970-01-01
    • 2021-02-11
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多