Ibatis ORA-00936: 缺失表达式 异常原因之一

用ibatis2.0做持久层开发,出现以下异常:

com.ibatis.common.jdbc.exception.NestedSQLException:   
--- The error occurred while applying a parameter map.  
--- Check the FINGERDB_MANAGERINFO.countByParams-InlineParameterMap.  
--- Check the statement (query failed).  
--- Cause: java.sql.SQLException: ORA-00936: 缺失表达式

Caused by: java.sql.SQLException: ORA-00936: 缺失表达式

	at com.ibatis.sqlmap.engine.mapping.statement.GeneralStatement.executeQueryWithCallback(GeneralStatement.java:185)
	at com.ibatis.sqlmap.engine.mapping.statement.GeneralStatement.executeQueryForObject(GeneralStatement.java:104)
	at com.ibatis.sqlmap.engine.impl.SqlMapExecutorDelegate.queryForObject(SqlMapExecutorDelegate.java:565)
	at com.ibatis.sqlmap.engine.impl.SqlMapExecutorDelegate.queryForObject(SqlMapExecutorDelegate.java:540)
	at com.ibatis.sqlmap.engine.impl.SqlMapSessionImpl.queryForObject(SqlMapSessionImpl.java:106)
	at com.ibatis.sqlmap.engine.impl.SqlMapClientImpl.queryForObject(SqlMapClientImpl.java:84)
	at data.ManagerInfoDao.countByParams(ManagerInfoDao.java:33)

 经排查,错误在此处:

<isNotEmpty prepend="AND" property="deptnos">
  	 			<iterate prepend="AND" property="deptnos" open="(" close=")" conjunction="or">
  	 				DEPTNO = #deptnos[]#
  	 			</iterate>
  	 		</isNotEmpty>

 去掉

prepend="AND"

 改成以下即可。

<isNotEmpty prepend="AND" property="deptnos">
  	 			<iterate property="deptnos" open="(" close=")" conjunction="or">
  	 				DEPTNO = #deptnos[]#
  	 			</iterate>
  	 		</isNotEmpty>

 

你遇到的错误是: ``` ORA-00936: 缺失表达式 ``` 结合 SQL 语句来看: ```sql SELECT * FROM ( SELECT TMP.*, ROWNUM ROW_ID FROM ( SELECT id, delivery_holder, ship_name, ship_voyage, inbound, outbound, volume_difference, receiving_time, source, approval_status, applicant, number, remarks, created_user, created_at, updated_at FROM JL_WATER_EXCEED ORDER BY created_at DESC ) TMP WHERE ROWNUM <= ? ) WHERE ROW_ID > ? ``` 这个 SQL 是 **Oracle 分页查询的经典写法**,语法本身在大多数情况下是对的。但报错 `ORA-00936: 缺失表达式` 表明 SQL 解析过程中某个地方缺少了必要的表达式(比如列名、条件、括号不匹配等),最常见的原因是:**字段名是 Oracle 关键字或保留字!** --- ## ✅ 错误原因分析 ### 🔍 根本原因: > 某个字段名是 Oracle 的 **关键字或保留字**,导致 SQL 解析失败。 查看你的查询字段列表: ```sql SELECT id, delivery_holder, ship_name, ship_voyage, inbound, outbound, volume_difference, receiving_time, source, approval_status, applicant, number, remarks, created_user, created_at, updated_at ``` 其中最可疑的是这两个字段: | 字段 | 是否为关键字 | 风险等级 | |------|-------------|--------| | `NUMBER` | ✅ 是 Oracle 关键字(常用于 `NUMBER(10)` 数据类型) | ⚠️ 极高 | | `SOURCE` | ✅ 是 Oracle 保留字(如 `CONNECT BY` 中使用) | ⚠️ 高 | 👉 当你在 SQL 中直接写 `SELECT ... number, source ...` 而不加引号时,Oracle 会把它们当作关键字处理,从而导致 **“缺失表达式”** 错误 —— 因为解析器以为你要定义类型或者语法结构,结果后面跟的是 `,` 或别名,语法断裂。 --- ## ✅ 解决方案 ### ✅ 方案一:用双引号 `" "` 包裹关键字字段(推荐) 修改实体类中的字段注解,使用 `@TableField` 指定带双引号的列名: ```java import com.baomidou.mybatisplus.annotation.TableField; public class WaterExceed { // 其他字段... @TableField("`number`") // MySQL 反引号 private String number; // 如果你用 MySQL @TableField("\"NUMBER\"") // Oracle 必须用双引号大写 private String number; @TableField("\"SOURCE\"") private String source; // getter/setter } ``` > 📝 注意: - Oracle 默认将未加引号的标识符转为大写。 - 所以如果你数据库里字段叫 `NUMBER`,就必须写成 `"NUMBER"`。 - 使用 MyBatis-Plus 时,必须通过 `@TableField` 显式告诉它要用双引号包裹。 --- ### ✅ 方案二:检查并重命名字段(长期建议) 如果可以修改数据库设计,建议避免使用 Oracle 关键字作为字段名。 #### 推荐替换方案: | 原字段 | 替代名称 | |-------|---------| | `number` → `serial_number`, `doc_number`, `apply_number` | | `source` → `data_source`, `source_type`, `origin` | 然后同步更新 Java 实体类和数据库表结构。 --- ### ✅ 方案三:启用 MyBatis 打印完整 SQL 日志,确认问题 在 `application.yml` 中开启日志输出: ```yaml mybatis-plus: configuration: log-impl: org.apache.ibatis.logging.stdout.StdOutImpl ``` 运行接口后观察控制台打印的真实 SQL,确认是否生成了类似: ```sql SELECT "NUMBER", "SOURCE" ... ``` 如果没有双引号,则说明注解没生效。 --- ### ✅ 方案四:验证表结构是否存在拼写错误 执行以下 SQL 确认字段真实名称(注意大小写): ```sql SELECT COLUMN_NAME, DATA_TYPE FROM USER_TAB_COLUMNS WHERE TABLE_NAME = 'JL_WATER_EXCEED' ORDER BY COLUMN_ID; ``` 确保字段确实是 `NUMBER` 和 `SOURCE`,而不是 `NUM`, `NO`, `SRC` 等。 --- ## ✅ 修复示例代码 ```java @TableName("JL_WATER_EXCEED") public class WaterExceed { private Long id; private String deliveryHolder; private String shipName; private String shipVoyage; private BigDecimal inbound; private BigDecimal outbound; private BigDecimal volumeDifference; private Date receivingTime; @TableField("\"SOURCE\"") private String source; private String approvalStatus; private String applicant; @TableField("\"NUMBER\"") private String number; private String remarks; private String createdUser; private Date createdAt; private Date updatedAt; // getters and setters... } ``` --- ## ❗常见误区提醒 | 错误做法 | 正确做法 | |--------|--------| | `@TableField("number")` | ❌ 应该是 `"\"NUMBER\""` | | 不加注解直接用 `number` | ❌ Oracle 会当成关键字 | | 认为只是字段不存在 | ❌ 实际是语法解析失败 | --- ## ✅ 总结 | 问题 | 原因 | 解决方法 | |------|------|-----------| | ORA-00936: 缺失表达式 | 使用了 Oracle 关键字字段(如 `NUMBER`, `SOURCE`)且未加引号 | 使用 `@TableField("\"NUMBER\"")` 包裹 | | SQL 报错位置不在明显处 | Oracle 错误定位不准,实际问题在 SELECT 列表 | 查看所有字段是否涉及保留字 | | 开发环境正常生产异常 | 不同数据库对关键字容忍度不同 | 统一规范命名,避免关键字 | --- ###
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值