【问题标题】:How to convert SQL query with sub query and count to JPA criteria builder如何将带有子查询和计数的 SQL 查询转换为 JPA 标准构建器
【发布时间】:2015-01-31 16:55:03
【问题描述】:

我正在尝试将此 SQL 查询转换为使用 JPA 标准构建器。 答案必须是双精度或浮点数。

SELECT CAST((COUNT(m.id) -
(SELECT COUNT(s.id) 
  FROM mobile_unit as s
  left JOIN incident as i ON s.incidentId=i.id
  JOIN organizational_unit as o ON s.organizationalUnitId=o.id
  WHERE (s.organizationalUnitId = 1 AND s.incidentId IS NULL))) AS float) 
/COUNT(m.id) 
FROM mobile_unit as m 
JOIN organizational_unit as o ON m.organizationalUnitId=o.id
WHERE m.organizationalUnitId = 1

【问题讨论】:

  • 我不确定为什么要使用子查询,因为它与外部查询没有任何关联。只在三个表之间进行一次查询,然后在 Java 中进行计算不是更有意义吗?此外,在incidentId 上加入incident,然后从中过滤掉非空值对我来说似乎完全多余。最后,您没有使用organizational_unit 的两个连接中的任何一个,那么为什么要打扰它们呢?
  • @DavidWallace 感谢您的评论。子查询返回我需要在外部查询中使用的计数答案。我需要子查询只返回 eventId 不为空的 mobile_unit 的计数,也许有更好的方法来做到这一点。加入原始单元仅用于项目后期的测试。一天结束时,我写了 2 个查询并在 java 代码中进行了计算,但我仍然想知道是否可以在 JPA 中进行计算。
  • 嗯,我想是的。我对将 JPA Criteria Builders 用于聚合函数有点含糊,这就是为什么我不愿写出答案的原因。但是在 SQL 中,您实际上所做的只是计算在 organizationsUnitId 为 1 的那些中,incidentId 不为 null 的 mobile_unit 行的比例。所有连接都是不相关的,可以完全删除。所以我能找到用 SQL 写这个的最短方法是SELECT CAST(COUNT(incidentId) AS FLOAT)/ COUNT(*) FROM mobile_unit WHERE organizationalUnitId = 1 - 这与你的 SQL 完全相同。我...的部分...
  • ... 不知道如何帮助您将算术放入 Criteria Builder。
  • 这个问题还没有解决吗?是查询返回 INT 值而不是 DECIMALFLOAT 的问题吗?

标签: java sql-server hibernate jpa


【解决方案1】:

在没有测试的情况下,这里是如何做到这一点的粗略草图。

CriteriaBuilder cb = entityManager.getCriteriaBuilder();
CriteriaQuery<Float> cq = cb.createQuery(Float.class);

Root<MobileUnit> root = cq.from(MobileUnit.class);
// Join is actually unnecessary
root.join("organizationalUnit", JoinType.INNER);
cq.where(cb.equal(
    root.get("organizationalUnitId"),
    1
));

Subquery<Long> subquery = cq.subquery(Long.class);
Root<MobileUnit> subRoot = subquery.from(MobileUnit.class);
// Actually these joins are unnecessary, but you requested them..
subRoot.join("incident", JoinType.LEFT);
subRoot.join("organizationalUnit", JoinType.INNER);

subquery.select(cb.count(subRoot.get("id")));
subquery.where(cb.and(
    subRoot.get("organizationalUnitId").eq(cb.literal(1)),
    subRoot.get("incidentId").isNull()
));

cq.select(cb.quot(
    cb.diff(
        cb.count(root.get("id")),
        subquery
    ).as(Float.class),
    cb.count(root.get("id"))
));

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-05-11
    • 2012-04-01
    • 2014-07-12
    • 2013-07-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多