<select id="selectReviewedInvoicePaymentInfo" resultType="com.digitalgd.pms.project.finance.invoiceVerification.vo.PaymentInvoiceAiResultVo"> SELECT spi.id paymentId, spi.project_id projectId, spi.project_code projectCode, spir.project_name projectName, spi.payment_code paymentCode, spi.gmt_create FROM s_payment_info spi LEFT JOIN s_project_info_record spir ON spi.fk_project_info_record_id = spir.id where spi.payment_approver_status=3 <if test="gmtCreate != null"> and spi.gmt_modified >= DATE_FORMAT(#{gmtCreate},'%Y-%m-%d %H:00:00') </if> </select> 改造这个sql,增加一个判断,如果#{gmtCreate}整点时间等于 spi.gmt_modified整点时间, 那就条件为and spi.gmt_modified >= #{gmtCreate},否则条件为 and spi.gmt_modified >= DATE_FORMAT(#{gmtCreate},'%Y-%m-%d %H:00:00'),请问如何改写mybatis xml语句
时间: 2025-07-26 12:28:34 浏览: 9
<think>根据用户问题,需要在MyBatis XML中根据传入的时间参数是否为整点来选择不同的SQL比较逻辑。具体来说,如果传入的时间是整点(例如2023-01-0112:00:00),则使用等于条件;如果不是整点,则使用大于等于和小于等于条件。我们可以使用MyBatis的动态SQL标签(如<if>和<choose>)来实现条件判断。但是,由于需要判断传入的时间是否为整点,这个判断逻辑在SQL中不易直接实现,因此我们可以在Java代码中先判断时间是否为整点,然后将判断结果作为一个额外的参数传递给MyBatis的Mapper。步骤:1.在Java代码中,检查传入的时间参数(假设为`gmtModified`)是否为整点。整点的特征是分钟、秒和毫秒部分都为0。2.将判断结果(布尔值)作为一个新的参数(例如`isWholeHour`)传递给Mapper。3.在XML中,根据`isWholeHour`的值选择不同的SQL条件。例如,假设我们有一个查询,根据修改时间(`spi.gmt_modified`)进行筛选。如果传入的时间是整点,则我们使用`=`;否则,我们使用范围条件(`>=`和`<`下一个整点)。但是,用户问题中并没有明确说明非整点时的具体范围条件。这里假设:如果传入的时间不是整点,那么我们需要查询的是从传入时间开始到下一个整点之前的数据(即传入时间所在的整点时间段)。例如,传入时间为'2023-01-0112:30:00',则查询12:00:00到13:00:00之间的数据(注意:不包括13:00:00)。然而,根据问题描述,我们也可以这样理解:-当传入整点时,我们只查询该整点时刻的数据(等于条件)。-当传入非整点时,我们查询从传入时间所在整点开始到下一个整点结束的数据(即该整点小时内的所有数据)。但是,问题中说的是“根据传入时间是否匹配整点时间选择不同的spi.gmt_modified查询条件”,所以我们需要明确:-整点:使用等于条件(spi.gmt_modified= #{gmtModified})-非整点:使用范围条件(spi.gmt_modified>=当前传入时间所在整点andspi.gmt_modified <下一个整点)因此,我们需要在Java代码中计算出两个值:-当前传入时间所在整点(floor到小时)-下一个整点(当前整点加一小时)然后,将这些值作为参数传递给Mapper。具体实现:1.在Java代码中:```java//假设传入的gmtModified是java.util.Date类型Date gmtModified= ...; //传入的时间//判断是否为整点Calendarcal= Calendar.getInstance();cal.setTime(gmtModified);intminutes =cal.get(Calendar.MINUTE);intseconds =cal.get(Calendar.SECOND);intmilliseconds= cal.get(Calendar.MILLISECOND);boolean isWholeHour= (minutes ==0&& seconds==0 &&milliseconds ==0);//计算当前传入时间所在的整点(向下取整到小时)cal.set(Calendar.MINUTE,0);cal.set(Calendar.SECOND,0);cal.set(Calendar.MILLISECOND,0);DatefloorHour= cal.getTime();//计算下一个整点(当前整点加一小时)cal.add(Calendar.HOUR_OF_DAY,1);Date nextHour =cal.getTime();//将这些参数放入Map或自定义对象中传递给MapperMap<String,Object>params =new HashMap<>();params.put("gmtModified", gmtModified);params.put("isWholeHour", isWholeHour);params.put("floorHour",floorHour);params.put("nextHour",nextHour);```2.在MyBatis的Mapper XML中,我们可以这样写:```xml<select id="selectByTime" resultType="...">SELECT*FROMsome_table spiWHERE<choose><when test="isWholeHour">spi.gmt_modified =#{gmtModified}</when><otherwise>spi.gmt_modified >=#{floorHour}AND spi.gmt_modified< #{nextHour}</otherwise></choose></select>```注意:这里使用了<choose>标签,根据`isWholeHour`的值选择不同的条件。但是,如果不想在Java代码中做这么多逻辑,也可以在XML中使用MyBatis的动态SQL结合OGNL表达式,但判断整点比较复杂,因为需要提取时间的分钟、秒等,而SQL函数在不同数据库中有差异,且MyBatis的OGNL不支持直接操作日期。因此,推荐在Java代码中处理。另外,用户提供的引用中有关于动态SQL的使用,特别是<if>和<where>标签,但这里我们使用<choose>更合适,因为两种情况是互斥的。引用[3]提到了<if>标签的使用,引用[4]展示了<where>和<if>的使用,我们可以参考这些写法,但这里我们使用<choose>。另外,注意在<otherwise>中使用了范围条件,并且使用了两个参数(floorHour和nextHour),这样避免在XML中进行日期计算,保证SQL的数据库无关性。因此,最终解决方案是在Java代码中预处理日期参数,然后在XML中使用<choose>标签。注意:在XML中,我们使用`<`符号需要使用转义,即`<`,但这里在CDATA中或者使用转义字符都可以。不过,在标签内部直接使用`<`可能会被解析为标签的开始,所以最好使用`<![CDATA[ ...]]>`包裹,或者使用转义。我们可以在条件中使用转义:```xmlspi.gmt_modified>=#{floorHour}AND spi.gmt_modified< #{nextHour}```或者使用CDATA:```xml<![CDATA[spi.gmt_modified >=#{floorHour}AND spi.gmt_modified< #{nextHour}]]>```但为了可读性,通常使用转义字符。因此,修改为:```xml<otherwise>spi.gmt_modified >= #{floorHour} ANDspi.gmt_modified <#{nextHour}</otherwise>```完整示例:```xml<select id="selectByTime" resultType="...">SELECT* FROMsome_tablespiWHERE<choose><whentest="isWholeHour">spi.gmt_modified= #{gmtModified}</when><otherwise>spi.gmt_modified>=#{floorHour}AND spi.gmt_modified< #{nextHour}</otherwise></choose></select>```注意:这里没有使用<where>标签,因为条件前面没有其他条件,且<choose>内部的条件一定会有一个被选中。如果整个WHERE子句可能被省略,那么应该使用<where>标签。但这里我们总是有条件,所以可以不用<where>标签。但如果还有其他条件,则需要使用<where>标签来动态处理WHERE关键字和AND/OR。例如,如果有其他条件,可以这样写:```xml<selectid="selectByTime"resultType="...">SELECT *FROM some_table spi<where><!--其他条件--><iftest="otherCondition!= null">AND other_column =#{otherCondition}</if><!--时间条件 --><choose><when test="isWholeHour">AND spi.gmt_modified= #{gmtModified}</when><otherwise>AND(spi.gmt_modified>=#{floorHour}AND spi.gmt_modified< #{nextHour})</otherwise></choose></where></select>```这样,如果整个<where>标签内部有内容,MyBatis会自动加上WHERE关键字,并且去掉开头的AND(或OR)。注意在<choose>里面的条件前加了AND,因为有可能前面有其他条件。总结:根据用户需求,我们通过Java代码预处理判断整点和计算整点时间,然后在MyBatis XML中使用动态SQL的<choose>标签实现不同的查询条件。相关问题:1.在MyBatis中如何传递多个参数?2.MyBatis动态SQL中<choose>和<if>有什么区别?3.在MyBatis中如何处理日期范围查询?4.如何避免MyBatis动态SQL中的条件因参数为空而失效?</think>### MyBatis动态SQL:根据传入时间是否整点选择不同查询条件
在MyBatis中实现根据传入时间是否为整点动态切换SQL条件,可通过以下方案实现:
#### 解决方案
```xml
<select id="selectByModifiedTime" resultMap="yourResultMap">
SELECT * FROM your_table spi
<where>
<!-- 其他条件 -->
<choose>
<!-- 当传入时间为整点时:精确匹配 -->
<when test="isWholeHour != null and isWholeHour">
AND spi.gmt_modified = #{gmtModified}
</when>
<!-- 非整点时:范围查询 -->
<otherwise>
AND spi.gmt_modified >= #{floorHour}
AND spi.gmt_modified < #{nextHour}
</otherwise>
</choose>
</where>
</select>
```
#### 关键实现说明
1. **Java层预处理参数**:
```java
// 在Service层计算并传递参数
public List<Entity> query(Date gmtModified) {
Map<String, Object> params = new HashMap<>();
// 判断是否为整点(分钟秒为0)
Calendar cal = Calendar.getInstance();
cal.setTime(gmtModified);
boolean isWholeHour = (cal.get(Calendar.MINUTE) == 0
&& cal.get(Calendar.SECOND) == 0);
// 计算整点时间范围
cal.set(Calendar.MINUTE, 0);
cal.set(Calendar.SECOND, 0);
Date floorHour = cal.getTime(); // 当前小时整点
cal.add(Calendar.HOUR, 1);
Date nextHour = cal.getTime(); // 下一小时整点
params.put("gmtModified", gmtModified);
params.put("isWholeHour", isWholeHour);
params.put("floorHour", floorHour);
params.put("nextHour", nextHour);
return mapper.selectByModifiedTime(params);
}
```
2. **动态SQL逻辑**:
- 使用 `<choose>`/`<when>`/`<otherwise>` 实现条件分支
- 整点时间:使用 `=` 精确匹配
- 非整点时间:使用 `>=` 和 `<` 进行小时级范围查询
- 注意使用 `<` 转义XML中的 `<` 符号
#### 执行效果
| 传入时间 | 生成SQL条件 |
|-------------------------|-------------------------------------|
| `2023-05-01 14:00:00` | `spi.gmt_modified = '2023-05-01 14:00:00'` |
| `2023-05-01 14:30:00` | `spi.gmt_modified >= '2023-05-01 14:00:00' AND spi.gmt_modified < '2023-05-01 15:00:00'` |
#### 注意事项
1. 时区处理:确保所有时间参数使用统一时区
2. 索引优化:范围查询需确保 `gmt_modified` 字段有索引
3. 空值处理:建议在 `<where>` 标签内处理,避免空条件问题[^4]
4. 日期精度:数据库时间精度需与Java代码匹配(如毫秒处理)
> 此方案通过将时间判断逻辑前置到Java层,避免在XML中处理复杂日期计算,符合MyBatis动态SQL的最佳实践[^2][^3]。范围查询使用半开区间 `[start, end)` 模式可确保时间边界精确匹配[^5]。
阅读全文
相关推荐


















