如何使用 JPA 进行求和(案例)

Posted

技术标签:

【中文标题】如何使用 JPA 进行求和(案例)【英文标题】:How to do a Sum(case when) using JPA 【发布时间】:2020-12-29 05:19:55 【问题描述】:

我没有太多在 SQL 和类似 JPA 的代码之间转换的背景知识,所以我想知道如何将以下代码转换为 JPA 语法?或者如果它甚至可能?提前致谢。

SELECT DLR_CD, COUNT(*),
SUM(CASE WHEN CMPLT_DT='0001-01-01' THEN 1 END),
SUM(CASE WHEN CMPLT_DT!='0001-01-01' THEN 1 END),
SUM(CASE WHEN YEAR(CMPLT_DT) = YEAR(CURRENT DATE)-1 THEN 1 END),
SUM(CASE WHEN YEAR(CMPLT_DT) = YEAR(CURRENT DATE) THEN 1 END),
SUM(CASE WHEN (CMPLT_DT IS NULL OR CMPLT_DT='0001-01-01') THEN A.RPR_LBR_HR ELSE 0 END)
FROM <db2 table 1> A
join <db2 table 2> B
on ANUN_IND='A'
AND B.PIP_PSP_NO=A.PIP_PSP_NO
--OPTIONAL PARAMS GO HERE
GROUP BY DLR_CD
FOR FETCH ONLY WITH UR;

编辑:更新了完整的、几乎没有修改过的查询。

【问题讨论】:

【参考方案1】:

使用标准 api 它看起来像这样:

    CriteriaBuilder cb = entityManager.getCriteriaBuilder();
    CriteriaQuery<YourPojo> cq = cb.createQuery(YourPojo.class);
    
    Root<Entity1> root = cq.from(Entity1.class);
    Join<Entity1,Entity2> join = root.join(Entity1_.entity2,JoinType.LEFT);
    /* 
     * the join by ID is implicit when using the .join method, the second
     * condition is added as follows (Since you don't indicate the alias, 
     * I assume it is a field from table 2):
     */
    join.on(cb.equal(join.get(Entity2_.anunInd),'A'));
    
    Calendar dayOne = Calendar.getInstance();
    dayOne.set(1, 0, 1);
    
    //Expression for first and second sum case
    Expression<Long> caseDate = cb.<Long>selectCase().when(cb.equal(root.get(Entity1_.cmpltDt),dayOne.getTime()), 1L).otherwise(0L);
    Expression<Long> sumDate = cb.sum(caseDate);
    
    //Expression for third sum case
    Expression<Long> caseDateWithYearM1 = cb.<Long>selectCase().when(
            cb.equal(cb.function("YEAR", Long.class, root.get(Entity1_.cmpltDt)),
                    cb.sum(cb.function("YEAR", Long.class, cb.literal(new Date())),-1))
            , 1L).otherwise(0L);
    Expression<Long> sumDateWithYearM1 = cb.sum(caseDateWithYearM1);
    
    //Expression for fourth sun case
    Expression<Long> caseDateWithYear = cb.<Long>selectCase().when(
            cb.equal(cb.function("YEAR", Long.class, root.get(Entity1_.cmpltDt)),
                    cb.function("YEAR", Long.class, cb.literal(new Date())))
            , 1L).otherwise(0L);
    Expression<Long> sumDateWithYear = cb.sum(caseDateWithYear);

    Expression<Long> caseNew = cb.<Long>selectCase().when(cb.or(
      cb.equal(root.get(Entity1_.cmpltDt),dayOne.getTime()),
      cb.equal(root.get(Entity1_.cmpltDt),dayOne.getTime())),
             root.get(Entity1_.rprLbrHr)).otherwise(0L);

    Expression<Long> sumNew = cb.sum(caseNew);

    
    cq.multiselect(
            root.get(Entity1_.dlrCd),
            cb.count(root.get(Entity1_.dlrCd)),
            sumDate,
            sumDate,
            sumDateWithYearM1,
            sumDateWithYear,
            sumNew
    );
    
    cq.groupBy(root.get(Entity1_.dlrCd));

    List<YourPojo> resultado = entityManager.createQuery(cq).getResultList();

你的 Pojo 必须有一个与多选方法具有相同参数(顺序和类型)的构造函数。

结果查询:

select
    entity1.DLR_CD as col_0_0_,
    count(entity1.DLR_CD) as col_1_0_,
    sum(case when entity1.CMPLT_DT=? then 1 else 0 
        end) as col_2_0_,
    sum(case when entity1.CMPLT_DT=? then 1  else 0 
        end) as col_3_0_,
    sum(case when extract(year from entity1.CMPLT_DT)=extract(year from ?)+-1 then 1 else 0 
        end) as col_4_0_,
    sum(case when extract(year from entity1.CMPLT_DT)=extract(year from ?) then 1 else 0 
        end) as col_5_0_ ,
    sum(case when entity1.CMPLT_DT is null or entity1.CMPLT_DT=? then entity1.RPR_LBR_HR else 0 
        end) as col_6_0_,
from
    entity1
left join
    entity2 on entity1.PIP_PSP_NO = entity2.PIP_PSP_NO and 
    entity2.ANUN_IND='A'
group by
    entity1.DLR_CD

【讨论】:

嘿,@JLazar0 你能聊聊这个吗? 把剩下的查询放上去,我们看到可以做,但是提前告诉大家,Union 做不到。有必要在没有它的情况下找到类似的查询,或者抛出几个查询并添加结果。您添加的内容带有 EDITED 标签,因此我给出的答案对于想要了解如何进行求和部分的人有效 我纠正自己,如果可以的话,使用命名查询,这与 JPA 哲学有些不同,但可以做到。 我已经更新了包含连接和新总和的答案,也许某些字段来自另一个实体,但它会更改引用表(根/连接)和元模型的对象用于提取参数。这是因为所有领域都没有别名,不知道模型。 我通常使用三层架构,负责公开 api 的控制层,负责管理事务性的服务层,以及您必须在其中创建使用此代码的方法。如果您可以使用 JPQL、本机查询、命名查询……我选择 Criteria 作为答案,因为您没有指定,我觉得更喜欢它,但是您有更多工具来进行查询。

以上是关于如何使用 JPA 进行求和(案例)的主要内容,如果未能解决你的问题,请参考以下文章

Vuex 核心概念基本使用 及 求和案例

Vuex 核心概念基本使用 及 求和案例

如何使用 jpa 规范添加不同的属性以进行查询

使用 JPA2 时如何对 EJB 进行单元测试?

使用 JPA2 时如何对 EJB 进行单元测试?

SQLite如何对`GridView`中列的值求和