动态sql是myBatis中相当有用的一个知识点,总体来说,动态sql有如下几类:
1>if语句(简单的条件判断)
2>choose(相当于case when),即C语言中的switth
3>trim(对包含的内容加上prefix(前缀)、或者suffix(后缀)等)
4>where(简化SQL语句中where条件判断)
5>set(用于 更新时设置)
6>foreach(实现myBatis in语句查询时有用)
如下例子均是普通sql操作的例子,如果采用oracle中的存储过程时,请直接看后面讲解。
一、if语句
使用环境举例:查询招聘列表,根据地点、薪资、工作经验等筛选条件进行筛选。
分析:这个时候,条件是动态的,可以全部选择,也可以只选择一部分。
动态SQL语句如下
<select id="getMyJobList" parameterType="com.zhiji.caren.VO.AttentionMyParams" resultMap="BaseResultMapJobList"> SELECT tall.LOCATION_ID, tall.LOCATION_NAME, tall.JOB_ID, tall.JOB_NAME, tall.NEGOTIABLE_FLAG, tall.SALARY_MAX, tall.SALARY_MIN, tall.ADD_TIME, tall.ENTERPRISE_ID, tall.ENTERPRISE_NAME, tall.ENTERPRISE_LOGO, tall.WORK_YEARS_ID, tall.WORK_YEARS_INFO, IFNULL( tujf.FOCUS_FLAG,0) as flag FROM (SELECT tj.JOB_ID, tj.LOCATION_ID, tl.LOCATION_NAME, tj.JOB_NAME, tj.NEGOTIABLE_FLAG, tj.SALARY_MAX, tj.SALARY_MIN, tj.ADD_TIME, tj.ENTERPRISE_ID, te.ENTERPRISE_NAME, te.ENTERPRISE_LOGO, twy.WORK_YEARS_ID, twy.WORK_YEARS_INFO, '' AS flag FROM t_job tj,t_location tl,t_enterprise te,t_hr th,t_work_years twy,t_job_category tjc,t_job_type tjt WHERE tj.LOCATION_ID = tl.LOCATION_ID AND tl.LOCATION_LEVEL = 2 AND tl.USE_FLAG = 1 AND tj.ENTERPRISE_ID = te.ENTERPRISE_ID AND te.USE_FLAG = 1 AND tj.HR_ID = th.HR_ID AND th.USE_FLAG = 1 AND tj.WORK_YEARS_ID = twy.WORK_YEARS_ID AND tj.JOB_CATEGORY_ID = tjc.JOB_CATEGORY_ID AND tjc.USE_FLAG = 1 AND tj.JOB_TYPE_ID = tjt.JOB_TYPE_ID AND tjt.USE_FLAG = 1 <if test="jobCategoryId != null"> AND tjc.JOB_CATEGORY_ID = #{jobCategoryId} </if> <if test="locationId != null"> AND tl.LOCATION_ID = #{locationId} </if> <if test="workYearId != null"> AND twy.WORK_YEARS_ID = #{workYearId} </if> <if test="jobTypeId != null"> AND tjt.JOB_TYPE_ID = #{jobTypeId} </if> <if test="lastTime != null"> AND tj.ADD_TIME <= #{lastTime} </if> GROUP BY tj.JOB_ID ORDER BY tj.ADD_TIME DESC) tall left join (select JOB_ID as FOCUS_JOB_ID,'1' as FOCUS_FLAG from t_user_job_focus where user_id = #{userId} and TYPE = '01') tujf on tall.JOB_ID = tujf.FOCUS_JOB_ID LIMIT #{pageIndex} </select>
备注:很明显,上面的if判断可以满足需求,只有当输入的条件不为空时(即选择了该筛选条件),SQL查询条件才带上这个筛选条件;否则,不带上这个筛选条件(即没有选择这个筛选条件)。
二、choose
它相当于C语言中的switch case。
适用场景:多选一的时候。
choose标签是按照顺序判断其内部when标签中的test条件是否成立,如果一旦成立,则choose语句结束;当choose中所有when条件都不满足时,则执行otherwise中的sql。
如上例子:筛选条件由多选变成单选
动态SQL语句如下
<select id="getMyJobList" parameterType="com.zhiji.caren.VO.AttentionMyParams" resultMap="BaseResultMapJobList"> SELECT tall.LOCATION_ID, tall.LOCATION_NAME, tall.JOB_ID, tall.JOB_NAME, tall.NEGOTIABLE_FLAG, tall.SALARY_MAX, tall.SALARY_MIN, tall.ADD_TIME, tall.ENTERPRISE_ID, tall.ENTERPRISE_NAME, tall.ENTERPRISE_LOGO, tall.WORK_YEARS_ID, tall.WORK_YEARS_INFO, IFNULL( tujf.FOCUS_FLAG,0) as flag FROM (SELECT tj.JOB_ID, tj.LOCATION_ID, tl.LOCATION_NAME, tj.JOB_NAME, tj.NEGOTIABLE_FLAG, tj.SALARY_MAX, tj.SALARY_MIN, tj.ADD_TIME, tj.ENTERPRISE_ID, te.ENTERPRISE_NAME, te.ENTERPRISE_LOGO, twy.WORK_YEARS_ID, twy.WORK_YEARS_INFO, '' AS flag FROM t_job tj,t_location tl,t_enterprise te,t_hr th,t_work_years twy,t_job_category tjc,t_job_type tjt WHERE tj.LOCATION_ID = tl.LOCATION_ID AND tl.LOCATION_LEVEL = 2 AND tl.USE_FLAG = 1 AND tj.ENTERPRISE_ID = te.ENTERPRISE_ID AND te.USE_FLAG = 1 AND tj.HR_ID = th.HR_ID AND th.USE_FLAG = 1 AND tj.WORK_YEARS_ID = twy.WORK_YEARS_ID AND tj.JOB_CATEGORY_ID = tjc.JOB_CATEGORY_ID AND tjc.USE_FLAG = 1 AND tj.JOB_TYPE_ID = tjt.JOB_TYPE_ID AND tjt.USE_FLAG = 1 <choose> <when test="jobCategoryId != null"> AND tjc.JOB_CATEGORY_ID = #{jobCategoryId} </when> <when test="locationId != null"> AND tl.LOCATION_ID = #{locationId} </when> <when test="workYearId != null"> AND twy.WORK_YEARS_ID = #{workYearId} </when> <when test="jobTypeId != null"> AND tjt.JOB_TYPE_ID = #{jobTypeId} </when> <when test="lastTime != null"> AND tj.ADD_TIME <= #{lastTime} </when> <otherwise> AND 1=1 </otherwise> </choose> GROUP BY tj.JOB_ID ORDER BY tj.ADD_TIME DESC) tall left join (select JOB_ID as FOCUS_JOB_ID,'1' as FOCUS_FLAG from t_user_job_focus where user_id = #{userId} and TYPE = '01') tujf on tall.JOB_ID = tujf.FOCUS_JOB_ID LIMIT #{pageIndex} </select>
说明:上述的SQL语句完成 筛选条件 多选一的时候。即筛选条件始终是只能选择一个或者不选。
三、trim
这个一般用得很少,我举一段用代码生成器生成的例子,如下
<insert id="insertSelective" parameterType="com.zhiji.caren.model.Job"> insert into t_job <trim prefix="(" suffix=")" suffixOverrides=","> <if test="jobId != null"> JOB_ID, </if> <if test="jobName != null"> JOB_NAME, </if> <if test="jobTypeId != null"> JOB_TYPE_ID, </if> <if test="jobDepartment != null"> JOB_DEPARTMENT, </if> <if test="enterpriseId != null"> ENTERPRISE_ID, </if> <if test="jobCategoryId != null"> JOB_CATEGORY_ID, </if> <if test="salaryMin != null"> SALARY_MIN, </if> <if test="salaryMax != null"> SALARY_MAX, </if> <if test="locationId != null"> LOCATION_ID, </if> <if test="hrId != null"> HR_ID, </if> <if test="workYearsId != null"> WORK_YEARS_ID, </if> <if test="eduRequirementId != null"> EDU_REQUIREMENT_ID, </if> <if test="jobDescription != null"> JOB_DESCRIPTION, </if> <if test="jobAddress != null"> JOB_ADDRESS, </if> <if test="auditFlag != null"> AUDIT_FLAG, </if> <if test="stikyFlag != null"> STIKY_FLAG, </if> <if test="negotiableFlag != null"> NEGOTIABLE_FLAG, </if> <if test="hrInfoFlag != null"> HR_INFO_FLAG, </if> <if test="useFlag != null"> USE_FLAG, </if> <if test="validTime != null"> VALID_TIME, </if> <if test="updUserId != null"> UPD_USER_ID, </if> <if test="addTime != null"> ADD_TIME, </if> <if test="updTime != null"> UPD_TIME, </if> </trim> <trim prefix="values (" suffix=")" suffixOverrides=","> <if test="jobId != null"> #{jobId,jdbcType=INTEGER}, </if> <if test="jobName != null"> #{jobName,jdbcType=VARCHAR}, </if> <if test="jobTypeId != null"> #{jobTypeId,jdbcType=INTEGER}, </if> <if test="jobDepartment != null"> #{jobDepartment,jdbcType=VARCHAR}, </if> <if test="enterpriseId != null"> #{enterpriseId,jdbcType=INTEGER}, </if> <if test="jobCategoryId != null"> #{jobCategoryId,jdbcType=INTEGER}, </if> <if test="salaryMin != null"> #{salaryMin,jdbcType=INTEGER}, </if> <if test="salaryMax != null"> #{salaryMax,jdbcType=INTEGER}, </if> <if test="locationId != null"> #{locationId,jdbcType=INTEGER}, </if> <if test="hrId != null"> #{hrId,jdbcType=INTEGER}, </if> <if test="workYearsId != null"> #{workYearsId,jdbcType=INTEGER}, </if> <if test="eduRequirementId != null"> #{eduRequirementId,jdbcType=INTEGER}, </if> <if test="jobDescription != null"> #{jobDescription,jdbcType=VARCHAR}, </if> <if test="jobAddress != null"> #{jobAddress,jdbcType=VARCHAR}, </if> <if test="auditFlag != null"> #{auditFlag,jdbcType=CHAR}, </if> <if test="stikyFlag != null"> #{stikyFlag,jdbcType=INTEGER}, </if> <if test="negotiableFlag != null"> #{negotiableFlag,jdbcType=INTEGER}, </if> <if test="hrInfoFlag != null"> #{hrInfoFlag,jdbcType=INTEGER}, </if> <if test="useFlag != null"> #{useFlag,jdbcType=INTEGER}, </if> <if test="validTime != null"> #{validTime,jdbcType=CHAR}, </if> <if test="updUserId != null"> #{updUserId,jdbcType=INTEGER}, </if> <if test="addTime != null"> #{addTime,jdbcType=CHAR}, </if> <if test="updTime != null"> #{updTime,jdbcType=CHAR}, </if> </trim> </insert>
上述是一条insert语句,去掉动态标签部分,学过SQL的人都应该看得懂。
这段代码<trim prefix="(" suffix=")" suffixOverrides=",">解释如下:
从<trim prefix="(" suffix=")" suffixOverrides=",">开始,如下那段代码后缀遇到","时,将那段代码用()括起来,同时,去掉最后的那个","号。
中间这段代码<trim prefix="values (" suffix=")" suffixOverrides=",">解释如下:
从<trim prefix="values (" suffix=")" suffixOverrides=",">开始,如下那段代码后缀遇到","时,那段代码的前面加上 values (,后面用 ")"代替","。
四、where
直接看例子
<select id="getMyJobListPart" parameterType="com.zhiji.caren.VO.AttentionMyParams" resultMap="BaseResultMapJobList"> SELECT tallTwo.JOB_ID, tallTwo.LOCATION_ID, tallTwo.LOCATION_NAME, tallTwo.JOB_NAME, tallTwo.NEGOTIABLE_FLAG, tallTwo.SALARY_MAX, tallTwo.SALARY_MIN, tallTwo.ADD_TIME, tallTwo.ENTERPRISE_ID, tallTwo.ENTERPRISE_NAME, tallTwo.ENTERPRISE_LOGO, tallTwo.WORK_YEARS_ID, tallTwo.WORK_YEARS_INFO, tallTwo.HR_ID, tallTwo.JOB_CATEGORY_ID, IFNULL( tujf.FOCUS_FLAG,0) as flag FROM (SELECT tall.JOB_ID, tall.LOCATION_ID, tl.LOCATION_NAME, tall.JOB_NAME, tall.NEGOTIABLE_FLAG, tall.SALARY_MAX, tall.SALARY_MIN, tall.ADD_TIME, tall.ENTERPRISE_ID, te.ENTERPRISE_NAME, te.ENTERPRISE_LOGO, tall.WORK_YEARS_ID, twy.WORK_YEARS_INFO, tall.HR_ID, tall.JOB_CATEGORY_ID, tall.JOB_TYPE_ID FROM ( SELECT tj.JOB_ID, tj.LOCATION_ID, tj.JOB_NAME, tj.NEGOTIABLE_FLAG, tj.SALARY_MAX, tj.SALARY_MIN, tj.ADD_TIME, tj.ENTERPRISE_ID, tj.WORK_YEARS_ID, tj.HR_ID, tj.JOB_CATEGORY_ID, tj.JOB_TYPE_ID FROM t_job tj <if test="salaryId != null"> ,t_salary ts </if> WHERE 1 = 1 <if test="salaryId != null"> AND ts.SALARY_ID = #{salaryId} AND ts.SALARY_MAX >=tj.SALARY_MAX AND ts.SALARY_MIN <= tj.SALARY_MIN </if> <if test="locationId != null"> AND tj.LOCATION_ID = #{locationId} </if> <if test="workYearId != null"> AND tj.WORK_YEARS_ID = #{workYearId} </if> <if test="jobCategoryId != null"> AND tj.JOB_CATEGORY_ID = #{jobCategoryId} </if> <if test="jobTypeId != null"> AND tj.JOB_TYPE_ID = #{jobTypeId} </if> <if test="lastTime != null"> AND tj.ADD_TIME <= #{lastTime} </if> GROUP BY tj.JOB_ID ORDER BY tj.ADD_TIME DESC ) tall LEFT JOIN t_location tl ON tall.LOCATION_ID = tl.LOCATION_ID AND tl.LOCATION_LEVEL = 2 AND tl.USE_FLAG = 1 LEFT JOIN t_enterprise te ON tall.ENTERPRISE_ID = te.ENTERPRISE_ID AND te.USE_FLAG = 1 LEFT JOIN t_hr th ON tall.HR_ID = th.HR_ID AND th.USE_FLAG = 1 LEFT JOIN t_work_years twy ON tall.WORK_YEARS_ID = twy.WORK_YEARS_ID LEFT JOIN t_job_category tjc ON tall.JOB_CATEGORY_ID = tjc.JOB_CATEGORY_ID AND tjc.USE_FLAG = 1 LEFT JOIN t_job_type tjt ON tall.JOB_TYPE_ID = tjt.JOB_TYPE_ID AND tjt.USE_FLAG = 1) tallTwo LEFT JOIN (select JOB_ID as FOCUS_JOB_ID,'1' as FOCUS_FLAG from t_user_job_focus where user_id = #{userId} and TYPE = '01') tujf ON tallTwo.JOB_ID = tujf.FOCUS_JOB_ID LIMIT #{pageIndex} </select>
如上动态SQL中有一个 where 1=1的地方,原本的情况应该写成这样
WHERE <if test="salaryId != null"> ts.SALARY_ID = #{salaryId} AND ts.SALARY_MAX >=tj.SALARY_MAX AND ts.SALARY_MIN <= tj.SALARY_MIN </if>
原本的情况下 当salaryId无值时,就会出现问题。改用where标签修改成如下:
tj.JOB_CATEGORY_ID, tj.JOB_TYPE_ID FROM t_job tj <if test="salaryId != null"> ,t_salary ts </if> <where> <if test="salaryId != null"> ts.SALARY_ID = #{salaryId} AND ts.SALARY_MAX >=tj.SALARY_MAX AND ts.SALARY_MIN <= tj.SALARY_MIN </if> ...... </where> GROUP BY tj.JOB_ID ......
说明:这种写法是 当<where>后的判断语句中有一条成立时,会在成立的语句之前加上where;如果成立的语句之前有AND或者OR,则mybatis会自动的去掉AND或OR。
五、set
主要是在update语句时使用
如下是我用代码生成器生成的一段代码如下
<update id="updateByPrimaryKeySelective" parameterType="com.zhiji.caren.model.Job"> update t_job <set> <if test="jobName != null"> JOB_NAME = #{jobName,jdbcType=VARCHAR}, </if> <if test="jobTypeId != null"> JOB_TYPE_ID = #{jobTypeId,jdbcType=INTEGER}, </if> <if test="jobDepartment != null"> JOB_DEPARTMENT = #{jobDepartment,jdbcType=VARCHAR}, </if> <if test="enterpriseId != null"> ENTERPRISE_ID = #{enterpriseId,jdbcType=INTEGER}, </if> <if test="jobCategoryId != null"> JOB_CATEGORY_ID = #{jobCategoryId,jdbcType=INTEGER}, </if> <if test="salaryMin != null"> SALARY_MIN = #{salaryMin,jdbcType=INTEGER}, </if> <if test="salaryMax != null"> SALARY_MAX = #{salaryMax,jdbcType=INTEGER}, </if> <if test="locationId != null"> LOCATION_ID = #{locationId,jdbcType=INTEGER}, </if> <if test="hrId != null"> HR_ID = #{hrId,jdbcType=INTEGER}, </if> <if test="workYearsId != null"> WORK_YEARS_ID = #{workYearsId,jdbcType=INTEGER}, </if> <if test="eduRequirementId != null"> EDU_REQUIREMENT_ID = #{eduRequirementId,jdbcType=INTEGER}, </if> <if test="jobDescription != null"> JOB_DESCRIPTION = #{jobDescription,jdbcType=VARCHAR}, </if> <if test="jobAddress != null"> JOB_ADDRESS = #{jobAddress,jdbcType=VARCHAR}, </if> <if test="auditFlag != null"> AUDIT_FLAG = #{auditFlag,jdbcType=CHAR}, </if> <if test="stikyFlag != null"> STIKY_FLAG = #{stikyFlag,jdbcType=INTEGER}, </if> <if test="negotiableFlag != null"> NEGOTIABLE_FLAG = #{negotiableFlag,jdbcType=INTEGER}, </if> <if test="hrInfoFlag != null"> HR_INFO_FLAG = #{hrInfoFlag,jdbcType=INTEGER}, </if> <if test="useFlag != null"> USE_FLAG = #{useFlag,jdbcType=INTEGER}, </if> <if test="validTime != null"> VALID_TIME = #{validTime,jdbcType=CHAR}, </if> <if test="updUserId != null"> UPD_USER_ID = #{updUserId,jdbcType=INTEGER}, </if> <if test="addTime != null"> ADD_TIME = #{addTime,jdbcType=CHAR}, </if> <if test="updTime != null"> UPD_TIME = #{updTime,jdbcType=CHAR}, </if> </set> where JOB_ID = #{jobId,jdbcType=INTEGER} </update>
看得懂纯SQL的人应该能看懂如上代码,<set>标签的作用主要是在中间那段代码的前面加上 set。如下是我没有使用<set>标签的更新语句,阅读者对比看下就能懂了。
<update id="updateByPrimaryKey" parameterType="com.zhiji.caren.model.Job"> update t_job set JOB_NAME = #{jobName,jdbcType=VARCHAR}, JOB_TYPE_ID = #{jobTypeId,jdbcType=INTEGER}, JOB_DEPARTMENT = #{jobDepartment,jdbcType=VARCHAR}, ENTERPRISE_ID = #{enterpriseId,jdbcType=INTEGER}, JOB_CATEGORY_ID = #{jobCategoryId,jdbcType=INTEGER}, SALARY_MIN = #{salaryMin,jdbcType=INTEGER}, SALARY_MAX = #{salaryMax,jdbcType=INTEGER}, LOCATION_ID = #{locationId,jdbcType=INTEGER}, HR_ID = #{hrId,jdbcType=INTEGER}, WORK_YEARS_ID = #{workYearsId,jdbcType=INTEGER}, EDU_REQUIREMENT_ID = #{eduRequirementId,jdbcType=INTEGER}, JOB_DESCRIPTION = #{jobDescription,jdbcType=VARCHAR}, JOB_ADDRESS = #{jobAddress,jdbcType=VARCHAR}, AUDIT_FLAG = #{auditFlag,jdbcType=CHAR}, STIKY_FLAG = #{stikyFlag,jdbcType=INTEGER}, NEGOTIABLE_FLAG = #{negotiableFlag,jdbcType=INTEGER}, HR_INFO_FLAG = #{hrInfoFlag,jdbcType=INTEGER}, USE_FLAG = #{useFlag,jdbcType=INTEGER}, VALID_TIME = #{validTime,jdbcType=CHAR}, UPD_USER_ID = #{updUserId,jdbcType=INTEGER}, ADD_TIME = #{addTime,jdbcType=CHAR}, UPD_TIME = #{updTime,jdbcType=CHAR} where JOB_ID = #{jobId,jdbcType=INTEGER} </update>
六、foreach
我用得比较少,这里不赘述,有需要的朋友可以参考如下地址
http://haohaoxuexi.iteye.com/blog/1338557