You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Hibernate新手求助:如何在WHERE子句中使用SUBSTRING

在Hibernate Criteria查询中使用SUBSTRING构建WHERE子句

嘿,作为Hibernate初学者,想要在Criteria查询里用SUBSTRING其实不难,我结合你的现有代码一步步给你讲清楚:

首先得明确你要对哪个字段做子串截取——假设你的实体类(对应daoClass)里有个目标字段,要么是字符串类型(比如存储成ddMMyyyy格式),要么是Date类型需要先转成字符串。下面分两种常见场景给你示例:

场景1:实体字段是字符串类型(存储为ddMMyyyy格式)

比如你想把传入的valDate转成ddMMyyyy格式后,和表中字段的某部分子串(比如年份、月份)做比较,可以这样修改代码:

public List<Table> getDaoByDate(Date valDate, boolean checkPast, Class daoClass) {
    EntityManager em = factory.createEntityManager();
    em.getTransaction().begin();
    CriteriaBuilder builder = factory.getCriteriaBuilder();
    CriteriaQuery criteriaQuery = builder.createQuery(daoClass);
    Root<?> table = criteriaQuery.from(daoClass);
    criteriaQuery.select(table);

    SimpleDateFormat sdf = new SimpleDateFormat("ddMMyyyy");
    String valDateStr = sdf.format(valDate);
    String[] let = { "A", "B", "CD" }; // 你原本的变量

    // 1. 构建SUBSTRING查询的条件:截取表中dateStr字段的年份部分(SQL的SUBSTRING是1-based索引,第5-8位)
    Expression<String> tableYearSub = builder.substring(table.get("dateStr"), 5, 4);
    String valYear = valDateStr.substring(4); // Java的substring是0-based,从索引4开始取年份
    Predicate yearMatch = builder.equal(tableYearSub, valYear);

    // 2. 结合checkPast参数添加时间范围条件
    Predicate dateRangePredicate;
    Expression<String> tableDateStr = table.get("dateStr");
    if (checkPast) {
        // 查询日期早于等于valDate的记录
        dateRangePredicate = builder.lessThanOrEqualTo(tableDateStr, valDateStr);
    } else {
        // 查询日期晚于等于valDate的记录
        dateRangePredicate = builder.greaterThanOrEqualTo(tableDateStr, valDateStr);
    }

    // 3. 把所有条件加入WHERE子句
    criteriaQuery.where(builder.and(yearMatch, dateRangePredicate));

    List<Table> result = em.createQuery(criteriaQuery).getResultList();
    em.getTransaction().commit();
    em.close();
    return result;
}

场景2:实体字段是Date类型

如果你的实体字段是Date类型,不能直接截取,需要先调用数据库的格式化函数把Date转成字符串,再用SUBSTRING:

这里以MySQL的DATE_FORMAT函数为例(Oracle可以用TO_CHAR,格式参数对应调整即可):

public List<Table> getDaoByDate(Date valDate, boolean checkPast, Class daoClass) {
    EntityManager em = factory.createEntityManager();
    em.getTransaction().begin();
    CriteriaBuilder builder = factory.getCriteriaBuilder();
    CriteriaQuery criteriaQuery = builder.createQuery(daoClass);
    Root<?> table = criteriaQuery.from(daoClass);
    criteriaQuery.select(table);

    SimpleDateFormat sdf = new SimpleDateFormat("ddMMyyyy");
    String valDateStr = sdf.format(valDate);
    String[] let = { "A", "B", "CD" };

    // 1. 把Date字段转成ddMMyyyy格式的字符串(调用MySQL的DATE_FORMAT函数)
    Expression<String> tableDateStr = builder.function(
        "DATE_FORMAT", 
        String.class, 
        table.get("valDate"), // 实体中的Date字段
        builder.literal("%d%m%Y") // 匹配ddMMyyyy的格式参数
    );

    // 2. 截取年份部分做比较
    Expression<String> tableYearSub = builder.substring(tableDateStr, 5, 4);
    String valYear = valDateStr.substring(4);
    Predicate yearMatch = builder.equal(tableYearSub, valYear);

    // 3. 结合checkPast添加范围条件
    Predicate dateRangePredicate;
    if (checkPast) {
        dateRangePredicate = builder.lessThanOrEqualTo(tableDateStr, valDateStr);
    } else {
        dateRangePredicate = builder.greaterThanOrEqualTo(tableDateStr, valDateStr);
    }

    criteriaQuery.where(builder.and(yearMatch, dateRangePredicate));

    List<Table> result = em.createQuery(criteriaQuery).getResultList();
    em.getTransaction().commit();
    em.close();
    return result;
}

关键注意点

  • Hibernate的CriteriaBuilder.substring()遵循SQL的索引规则,起始位置是1-based,和Java原生的String.substring()(0-based)不一样,别搞混了!
  • 如果是Date类型字段,要根据你使用的数据库选择对应的格式化函数,通过builder.function()调用数据库原生方法。
  • 可以用builder.and()/builder.or()组合多个Predicate,灵活构建复杂的WHERE条件。

内容的提问来源于stack exchange,提问作者sala

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.20 12:12:03