关于oracle中 != 及 null 使用注意点

本文深入探讨了在SQL查询中处理null值的常见问题,特别是使用等号和不等号进行比较时的注意事项。通过具体示例展示了如何正确地使用isnull、isnotnull和NVL函数来避免查询错误。

titlestepname 

关于继续开展下半年度集团早高峰保驾工作的通知传阅

 关于继续开展下半年度集团早高峰保驾工作的通知null

关于配合国资委协同办公平台统一权限配置的相关事宜null


执行如下语句:

select t.title,t.stepname from t_todo_item t where t.loginname='ST/G00100000161' and t.stepname!='传阅'

返回结果为空;


执行如下语句,结果才是希望得到的结果(stepName!='传阅')

select t.title,t.stepname from t_todo_item t where t.loginname='ST/G00100000161' and (t.stepname!='传阅' or t.stepname is null)

 关于继续开展下半年度集团早高峰保驾工作的通知null
关于配合国资委协同办公平台统一权限配置的相关事宜 null


因为null 不能用 = 或 != 来作为判断,只能使用 is null 或者 is not null

所以当 stepname!='传阅'时,null 未符合条件,故第一句的sql 是错误的。

也可以使用 nvl 函数

select t.title,t.stepname from t_todo_item t where t.loginname='ST/G00100000161' and nvl(t.stepname,'123')!='传阅'


总之,需要注意的就是 oracle 中的 null 不能用 =及!=用来比较 ,只能使用is null 或者 is not null,

当字段中有null时,需要区别对待。

说明: 
1、等价于没有任何值、是未知数。 
2、NULL与0、空字符串、空格都不同。 
3、对空值做加、减、乘、除等运算操作,结果仍为空。 
4、NULL的处理使用NVL函数。 
5、比较时使用关键字用“is null”和“is not null”。 
6、空值不能被索引,所以查询时有些符合条件的数据可能查不出来,count(*)中,用nvl(列名,0)处理后再查。 
7、排序时比其他数据都大(索引默认是降序排列,小→大),所以NULL值总是排在最后。 

foreach 内嵌入 <trim prefix="(" suffix=")" suffixOverrides=","> <if test="searchValue != null">searchvalue,</if> <if test="createBy != null">createby,</if> <if test="createTime != null">createtime,</if> <if test="updateBy != null">updateby,</if> <if test="updateTime != null">updatetime,</if> <if test="remark != null">remark,</if> <if test="params != null">params,</if> <if test="id != null">id,</if> <if test="serialId != null and serialId != ''">serialid,</if> <if test="purchaserOrganizationId != null and purchaserOrganizationId != ''">purchaserorganizationid,</if> <if test="organizationId != null and organizationId != ''">organizationid,</if> <if test="vehicleId != null and vehicleId != ''">vehicleid,</if> <if test="purchaserOrganizationCode != null">purchaserorganizationcode,</if> <if test="erpPlantCd != null">erpplantcd,</if> <if test="materialCode != null">materialcode,</if> <if test="vehicleSeries != null">vehicleseries,</if> <if test="batchNo != null and batchno != ''">batchno,</if> <if test="arrivalYymm != null and arrivalYymm != ''">arrivalyymm,</if> <if test="quantity != null and quantity != ''">quantity,</if> <if test="contractNo != null and contractNo != ''">contractno,</if> <if test="lotNo != null and lotNo != ''">lotno,</if> <if test="itemId != null and itemId != ''">itemid,</if> <if test="itemCode != null">itemcode,</if> <if test="partDiv != null">partdiv,</if> <if test="kdType != null">kdtype,</if> <if test="pushFlag != null">pushflag,</if> </trim> <trim prefix="values (" suffix=")" suffixOverrides=","> <if test="searchValue != null">#{searchValue},</if> <if test="createBy != null">#{createBy},</if> <if test="createTime != null">#{createTime},</if> <if test="updateBy != null">#{updateBy},</if> <if test="updateTime != null">#{updateTime},</if> <if test="remark != null">#{remark},</if> <if test="params != null">#{params},</if> <if test="id != null">#{id},</if> <if test="serialId != null and serialId != ''">#{serialId},</if> <if test="purchaserOrganizationId != null and purchaserOrganizationId != ''">#{purchaserOrganizationId},</if> <if test="organizationId != null and organizationId != ''">#{organizationId},</if> <if test="vehicleId != null and vehicleId != ''">#{vehicleId},</if> <if test="purchaserOrganizationCode != null">#{purchaserOrganizationCode},</if> <if test="erpPlantCd != null">#{erpPlantCd},</if> <if test="materialCode != null">#{materialCode},</if> <if test="vehicleSeries != null">#{vehicleSeries},</if> <if test="batchNo != null and batchNo != ''">#{batchNo},</if> <if test="arrivalYymm != null and arrivalYymm != ''">#{arrivalYymm},</if> <if test="quantity != null and quantity != ''">#{quantity},</if> <if test="contractNo != null and contractNo != ''">#{contractNo},</if> <if test="lotNo != null and lotNo != ''">#{lotNo},</if> <if test="itemId != null and itemId != ''">#{itemId},</if> <if test="itemCode != null">#{itemCode},</if> <if test="partDiv != null">#{partDiv},</if> <if test="kdType != null">#{kdType},</if> <if test="pushFlag != null">#{pushFlag},</if> </trim>
最新发布
11-15
<think> 我们讨论的是在MyBatis的XML映射文件中,如何在<foreach>循环内部使用带有多个<if>条件的<trim>标签。这种结构通常用于动态生成复杂的SQL片段,特别是在批量操作中需要根据条件动态调整插入或更新的字段时。 ### 使用场景 假设有一个批量插入操作,但不同记录可能需要插入不同的字段(例如:某些记录可能不需要插入某些字段,或者某些字段的值需要根据条件计算)。此时,在<foreach>内部结合<trim>和<if>可以动态生成每一行要插入的字段和值。 ### 示例代码 以下是一个在批量插入中使用<foreach>内嵌<trim>和多个<if>条件的例子: ```xml <insert id="batchInsertUsers" parameterType="java.util.List"> INSERT INTO users (uuid, account <if test="list[0].userName != null">, user_name</if> <!-- 注意:这里判断第一个元素,假设所有元素该字段存在性一致 --> <if test="list[0].pwd != null">, pwd</if> <if test="list[0].orgUuid != null">, org_uuid</if> ) VALUES <foreach collection="list" item="item" index="index" separator=","> ( #{item.uuid}, #{item.account} <!-- 使用trim标签处理动态字段值的逗号问题 --> <trim prefix="," suffixOverrides=","> <if test="item.userName != null"> #{item.userName}, </if> <if test="item.pwd != null"> #{item.pwd}, </if> <if test="item.orgUuid != null"> #{item.orgUuid}, </if> </trim> ) </foreach> </insert> ``` ### 注意事项 1. **字段列表与值列表的对应**:字段列表(INSERT INTO后的括号内)和值列表(VALUES后的每个括号内)必须一一对应。由于字段列表是动态生成的,我们通常假设同一个批次中的所有记录具有相同的非空字段(即如果第一个记录的某个字段非空,则整个批次的该字段都不为空)。因此,我们在字段列表中使用`list[0]`来判断第一个元素的字段非空情况,从而决定整个批次的字段列表。 2. **值列表中的逗号处理**:在值列表的<foreach>内部,我们使用<trim>标签来动态生成字段值。注意: - `prefix=","`:表示如果<trim>内部有内容,则在内容之前添加一个逗号。 - `suffixOverrides=","`:表示如果内容最后有多余的逗号,则去除。这样,即使最后一个条件不满足,也不会留下多余的逗号。 3. **性能考虑**:动态SQL的解析会带来一定的性能开销,尤其是在批量数据量大的情况下。因此,建议在应用层确保同一批次的数据具有相同的字段结构(即非空字段一致),这样可以避免在每条记录上都进行动态判断。 4. **空值处理**:如果某个字段可能为null,并且数据库表允许为null,则可以通过<if>条件判断来跳过该字段。但如果数据库表要求该字段非空,则必须确保该字段有值,否则会报错。 5. **索引越界问题**:在字段列表的判断中,我们使用了`list[0]`,因此要确保传入的list至少有一个元素。如果list可能为空,需要在Java代码中进行判断,避免执行SQL。 ### 优化建议 - **减少动态判断**:如果可能,尽量保证同一批次的数据结构相同,这样可以在字段列表中使用一次判断(基于第一个元素),而避免在值列表的每条记录中都进行相同的判断(因为字段列表已经固定了,值列表中的字段顺序和数量是确定的,所以可以不用<trim>)。例如: ```xml <insert id="batchInsertUsers" parameterType="java.util.List"> <choose> <when test="list[0].userName != null and list[0].pwd != null"> INSERT INTO users (uuid, account, user_name, pwd) VALUES <foreach collection="list" item="item" separator=","> (#{item.uuid}, #{item.account}, #{item.userName}, #{item.pwd}) </foreach> </when> <when test="list[0].userName != null"> INSERT INTO users (uuid, account, user_name) VALUES <foreach collection="list" item="item" separator=","> (#{item.uuid}, #{item.account}, #{item.userName}) </foreach> </when> <otherwise> INSERT INTO users (uuid, account) VALUES <foreach collection="list" item="item" separator=","> (#{item.uuid}, #{item.account}) </foreach> </otherwise> </choose> </insert> ``` 这种方法将不同的字段组合拆分成多个静态的SQL,避免了在每条记录中动态判断,提高了性能,但增加了代码量。 ### 总结 在MyBatis中,在<foreach>内使用<trim>和多个<if>条件可以实现复杂的动态SQL批量操作。使用时需要注意字段列表和值列表的对应关系、逗号的处理以及性能问题。如果同一批次的数据结构一致,建议将动态判断提升到字段列表一级,避免在每条记录中判断。 §§相关问题§§ 1. MyBatis中如何批量更新(update)带有动态字段的数据? 2. MyBatis动态SQL中<trim>标签的prefix和suffixOverrides属性如何使用? 3. 如何避免MyBatis批量操作时的SQL注入风险? 4. MyBatis批量插入时如何返回自增主键(Oracle和MySQL)? 5. MyBatis中<foreach>标签的collection属性有哪些用法? </think> ### MyBatis中`<foreach>`内嵌`<trim>`与多条件`<if>`的使用指南 在MyBatis动态SQL中,组合使用`<foreach>`、`<trim>`和多个`<if>`标签能实现复杂条件批量操作,尤其适用于动态字段的批量插入/更新场景。 #### 基础语法结构 ```xml <foreach collection="list" item="item"> <trim prefix="(" suffix=")" suffixOverrides=","> <if test="item.field1 != null"> #{item.field1}, </if> <if test="item.field2 != null and item.field2 != ''"> #{item.field2}, </if> <!-- 更多条件判断 --> </trim> </foreach> ``` #### 完整批量插入示例 ```xml <insert id="batchInsert"> INSERT INTO users <foreach collection="list" item="item" open="(" separator="," close=")"> <trim suffixOverrides=","> <if test="item.id != null">id,</if> <if test="item.name != null">name,</if> <if test="item.age gt 0">age,</if> <!-- 年龄大于0才插入 --> </trim> </foreach> VALUES <foreach collection="list" item="item" separator=","> <trim prefix="(" suffix=")" suffixOverrides=","> <if test="item.id != null">#{item.id},</if> <if test="item.name != null">#{item.name},</if> <if test="item.age gt 0">#{item.age},</if> </trim> </foreach> </insert> ``` #### 关键注意事项 1. **字段与值的对齐** - 字段列表`<foreach>`和值列表`<foreach>`必须保持**完全相同的结构** - 建议使用相同的`<if>`条件判断逻辑 2. **逗号处理** ```xml <trim suffixOverrides=","> <!-- 自动移除尾部多余逗号 --> ... </trim> ``` 3. **空值处理** - 使用`<if test="field != null"`过滤null值 - 对于空字符串:`<if test="field != null and field != ''"` 4. **性能优化** ```java // Java代码分批处理(防止SQL过长) for (int i=0; i<list.size(); i+=500) { mapper.batchInsert(list.subList(i, Math.min(i+500, list.size()))); } ``` 5. **动态条件优先级** ```xml <!-- 使用choose-when处理互斥条件 --> <choose> <when test="item.type == 'A'"> #{item.valueA}, </when> <when test="item.type == 'B'"> #{item.valueB}, </when> <otherwise> DEFAULT, </otherwise> </choose> ``` #### 复杂条件示例(批量更新) ```xml <update id="batchUpdate"> UPDATE table <trim prefix="SET" suffixOverrides=","> <foreach collection="list" item="item"> <if test="item.status != null"> status = <choose> <when test="item.status == 0">'PENDING'</when> <when test="item.status == 1">'APPROVED'</when> </choose>, </if> <if test="item.amount != null"> amount = amount + #{item.amount}, </if> </foreach> </trim> WHERE id IN <foreach collection="list" item="item" open="(" separator="," close=")"> #{item.id} </foreach> </update> ``` #### 常见错误解决方案 1. **SQL语法错误** - 现象:`org.apache.ibatis.exceptions.PersistenceException` - 对策:启用MyBatis日志,检查生成的完整SQL ```xml <settings> <setting name="logImpl" value="STDOUT_LOGGING"/> </settings> ``` 2. **条件判断失效** - 确保对象属性命名正确 - 使用OGNL表达式调试:`<if test="@java.util.Objects@nonNull(item.field)">` 3. **批量操作事务回滚** ```java try { mapper.batchInsert(list); } catch (Exception e) { sqlSession.rollback(); // 手动回滚 throw new BatchOperationException("批量操作失败"); } ``` --- ### 最佳实践建议 1. **字段一致性检查**:在Java层确保同批次字段存在性一致 2. **批处理大小**:每批500-1000条记录 3. **单元测试验证**:使用MyBatis-Spring-Boot-Test验证SQL生成 4. **索引优化**:对WHERE条件字段建立索引 5. **安全防护**:防止SQL注入 ```xml <!-- 永远不要这样用! --> ORDER BY ${sortField} <!-- 危险! --> <!-- 应该用 --> ORDER BY <choose> <when test="sortField == 'name'">name</when> <otherwise>id</otherwise> </choose> ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值