精华内容
下载资源
问答
  • 这不,老板刚刚发了份每个员工的每月销量,让做成图表给他,要求要清晰明确,可以随意查看每个员工的状态。如果我们直接做出来这样图,横坐标是每个月,每个月里面把每个人数据都整合在一起,这样的图表肯定不能给...

    ​马上就要到年终了,又要到开始到每年的年终总结上了。这不,老板刚刚发了份每个员工的每月销量表,让做成图表给他,要求要清晰明确,可以随意查看每个员工的状态。

    4dea73e171d5e2e32ad88195122bd7ca.png

    如果我们直接做出来这样图,横坐标是每个月,每个月里面把每个人数据都整合在一起,这样的图表肯定不能给领导吧。

    486d0fb4003417584388e6d9c8636a90.png


    那什么样的图比较适合呢?比较好看而且实用的,还可以根据员工姓名随意切换图表呢?肯定要做成动态图表了,就像下面这样的。

    0e88bd73e4a199be7362ea4792e58c3b.gif


    当我们切换员工的名称,数据图表也跟着一起变换,并把销量最大最小的用不同颜色标记出来了,这是如何实现的呢?

    操作步骤:

    1、首先点击菜单栏中的【开发工具】-【插入】-【组合框】,如下图所示

    06662efec3fb7e38542e7f2662fd128e.png


    2、右击插入的组合框,【设置控件格式】-【控制】,在弹出的对话框中输入如下信息:

    数据源区域:A2:A9

    单元格链接:A15

    30b556d88e757b9d1c3084260e7211f5.gif

    当我们点击控件下拉按钮的时候,可以显示A列姓名,并且会在A15显示此名称在A列姓名列的第几行

    比如选择"李白",可发现A15显示为2,代表"李白"在A2:A9中的第二行。

    3、根据A15显示的行数,提取A列名称,使其和控件保持一致

    在A16输入公式:=INDEX(A2:A9,A15)

    可以发现当控件内容发生变化的时候,A16单元格的内容也跟着一起变化了

    fd94d0622aa0c64d79afa29ca3293fa4.gif


    4、输出月份信息

    在A17输入公式:

    =IF(OFFSET($B$1,,ROW(1:1)-1)="","",OFFSET($B$1,,ROW(1:1)-1))

    980b67aba5aa67f6ef1dffcc3b3c564c.png

    此处使用的是OFFSET函数,目的是把B1单元格向右移动ROW(1:1)-1列,

    ROW(1:1)代表1,ROW(12:12)代表12

    A28行的公式为

    =IF(OFFSET($B$1,,ROW(12:12)-1)="","",OFFSET($B$1,,ROW(12:12)-1))

    即为把B1单元格的向右移动11列,即得到M1的内容:12月

    5、使用INDEX和MATCH函数,提取个人销量数据

    在B17单元格输入公式:

    =INDEX($B$2:$M$9,MATCH($A$16,$A$2:$A$9,0),MATCH(A17,$B$1:$M$1,0))

    fd59bd24cf73ae36b634c4672e732956.gif

    6、提取数据的最大最小值

    分别在C17和D17单元格输入如下公式:

    =IF(MAX($B$17:$B$28)=B17,B17,NA()) 'C17单元格公式

    =IF(MIN($B$17:$B$28)=B17,B17,NA()) 'D17单元格公式

    最终显示数据图如下:

    ea623fa0e228d66d27686434611f6d83.png

    7、选择A17:D28,按Alt+F1插入柱形图表

    6ba7b8e953e0092432079d4e137d1558.png


    8、设置图表样式,点击柱形图,右击【设置数据序列格式】

    系列重叠:100%,分类间距:50%

    e41c9db1df52f6061fa3eff3eafaa449.gif

    9、美化图表:删除网格线,重命名标题,设置外框,添加数据标签,把控件和图表组合起来

    d474ee265c4d97ea9079135ac9b1fe95.gif


    这样一个漂亮的销量图表就制作完成了,中间我们用到了【开发工具】里面的组合框控件,INDEX函数,MATCH函数,OFFSET函数,IFERROR函数,MAX及MIN函数等等,每个函数及操作形成了这个图表的一部分构成,最终实现了我们想要的图形。

    0e88bd73e4a199be7362ea4792e58c3b.gif

    快快去练习下吧~~

    如果觉得文章对你有帮助的话,希望大家帮忙点赞加分享哦~,谢谢

    本文由彩虹Excel原创,欢迎关注,带你一起长知识!

    更多内容,请关注"彩虹Excel",学习更多知识,谢谢~

    展开全文
  • 在上一章中我们学习了《MyBatis学习总结(二)——MyBatis核心配置文件与输入输出映射》,这一章主要是介绍一对一关联查询、一对多关联查询与动态SQL等内容。 一、多关联查询 之间有三种常见的关联关系,...

    在上一章中我们学习了《MyBatis学习总结(二)——MyBatis核心配置文件与输入输出映射》,这一章主要是介绍一对一关联查询、一对多关联查询与动态SQL等内容。

    一、多表关联查询

    表与表之间有三种常见的关联关系,分别是一对一,一对多与多对多关系,MyBatis直接提供一对一与一对多的关联关系,可能通过间接的方式实现一对多关联。

    1.1、一对一关系

    1.1.1、执行环境

    假定一个员工(emp)拥有一个登录用户(user),员工与用户表之间是一对一关系:

     用户表:

    员工表:

    SQL:

    SET FOREIGN_KEY_CHECKS=0;
    
    -- ----------------------------
    -- Table structure for `user`
    -- ----------------------------
    DROP TABLE IF EXISTS `user`;
    CREATE TABLE `user` (
     `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '编号',
     `username` varchar(64) NOT NULL COMMENT '用户名',
     `password` varchar(64) NOT NULL COMMENT '密码',
     PRIMARY KEY (`id`),
     UNIQUE KEY `users_username_uindex` (`username`)
    ) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8 COMMENT='用户表';
    
    -- ----------------------------
    -- Records of user
    -- ----------------------------
    INSERT INTO `user` VALUES ('1', 'tom', '123456');
    INSERT INTO `user` VALUES ('2', 'rose', '888888');
    INSERT INTO `user` VALUES ('3', 'mark', 'qwerty');
    INSERT INTO `user` VALUES ('4', 'jack', 'qaz123');
    INSERT INTO `user` VALUES ('5', 'mali', 'uio890');
    
    SET FOREIGN_KEY_CHECKS=0;
    
    -- ----------------------------
    -- Table structure for `emp`
    -- ----------------------------
    DROP TABLE IF EXISTS `emp`;
    CREATE TABLE `emp` (
     `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '编号',
     `user_id` int(11) DEFAULT NULL COMMENT '用户编号',
     `realname` varchar(32) NOT NULL COMMENT '姓名',
     `email` varchar(64) DEFAULT NULL COMMENT '邮箱',
     PRIMARY KEY (`id`),
     KEY `emp_user_id` (`user_id`),
     CONSTRAINT `emp_user_id` FOREIGN KEY (`user_id`) REFERENCES `user` (`id`)
    ) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8 COMMENT='员工表';
    
    -- ----------------------------
    -- Records of emp
    -- ----------------------------
    INSERT INTO `emp` VALUES ('1', '1', '汤姆', 'tom@gmail.com');
    INSERT INTO `emp` VALUES ('2', '2', '梅贵', 'rose@163.com');
    INSERT INTO `emp` VALUES ('3', '3', '马克', 'mark@sina.com');
    INSERT INTO `emp` VALUES ('4', '4', '岳翰', 'jack@gmail.com');
    INSERT INTO `emp` VALUES ('5', '5', '马丽', 'mali@sina.com');

    关系:

    1.1.2、关联查询(1次查询)

    实体:

      用户:

    package com.zhangguo.mybatis03.entities;
    
    /**用户POJO*/
    public class User {
     private int id;
     private String username;
     private String password;
    
     public int getId() {
     return id;
     }
    
     public void setId(int id) {
     this.id = id;
     }
    
     public String getUsername() {
     return username;
     }
    
     public void setUsername(String username) {
     this.username = username;
     }
    
     public String getPassword() {
     return password;
     }
    
     public void setPassword(String password) {
     this.password = password;
     }
    }

      员工:

    package com.zhangguo.mybatis03.entities;
    
    /**员工POJO*/
    public class Emp {
     private int id;
     /**用户编号*/
     private int user_id;
     private String realname;
     private String email;
    
     /**用户对象*/
     private User user;
    
     public int getId() {
     return id;
     }
    
     public void setId(int id) {
     this.id = id;
     }
    
     public int getUser_id() {
     return user_id;
     }
    
     public void setUser_id(int user_id) {
     this.user_id = user_id;
     }
    
     public String getRealname() {
     return realname;
     }
    
     public void setRealname(String realname) {
     this.realname = realname;
     }
    
     public String getEmail() {
     return email;
     }
    
     public void setEmail(String email) {
     this.email = email;
     }
    
     public User getUser() {
     return user;
     }
    
     public Emp setUser(User user) {
     this.user = user;
     return this;
     }
    }

    接口:

    package com.zhangguo.mybatis03.dao;
    
    import com.zhangguo.mybatis03.entities.Emp;
    
    /**员工数据访口*/
    public interface EmpMapper {
    
     /**获得员工通过员工编号*/
     Emp getEmpById_1(int id);
    
    }

    映射:

    <?xml version="1.0" encoding="UTF-8" ?>
    
    <!DOCTYPE mapper
     PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
     "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    <mapper namespace="com.zhangguo.mybatis03.dao.EmpMapper">
    
     <!--一对一查询,方法1,通过内联接-->
     <select id="getEmpById_1" resultMap="empMap_1" parameterType="int">
     SELECT
     emp.id,
     emp.user_id,
     emp.realname,
     emp.email,
     `user`.username,
     `user`.`password`
     FROM
     emp
     INNER JOIN `user` ON emp.user_id = `user`.id where emp.id=#{id}
     </select>
    
     <!--员工关联查询结果映射-->
     <resultMap id="empMap_1" type="Emp">
     <id property="id" column="id"></id>
     <result property="user_id" column="user_id"></result>
     <result property="realname" column="realname"></result>
     <result property="email" column="email"></result>
     <!--映射关系,指定属性与属性的类型-->
     <association property="user" javaType="User">
     <id property="id" column="user_id"></id>
     <result property="username" column="username"></result>
     <result property="password" column="password"></result>
     </association>
     </resultMap>
    
    </mapper>

    测试:

    package com.zhangguo.mybatis03.dao;
    
    import com.zhangguo.mybatis03.entities.Emp;
    import org.junit.Assert;
    import org.junit.Test;
    import org.junit.Before;
    import org.junit.After;
    
    /**
     * EmpDao Tester.
     *
     * @author <Authors name>
     * @version 1.0
     * @since <pre>09/30/2018</pre>
     */
    public class EmpDaoTest {
     EmpMapper empDao;
     @Before
     public void before() throws Exception {
     empDao=new EmpDao();
     }
    
     @After
     public void after() throws Exception {
     }
    
     /**
     * Method: getEmpById_1(int id)
     * 获得员工通过员工编号
     */
     @Test
     public void testGetEmpById_1() throws Exception {
     Emp entity=empDao.getEmpById_1(1);
     System.out.println(entity);
     Assert.assertNotNull(entity);
     }
    
    
    } 

    结果:

    1.1.3、嵌套查询(2次查询)

    实体:同上

    接口:

     /**获得员工通过员工编号,多次查询*/
     Emp getEmpById_2(int id);

    映射:

     <!--一对一查询,方法2,通过多次查询(嵌套查询)-->
     <select id="getEmpById_2" resultMap="empMap_2">
     SELECT
     emp.id,
     emp.user_id,
     emp.realname,
     emp.email
     FROM
     emp where id=#{id}
     </select>
    
     <!--员工多次查询结果映射-->
     <resultMap id="empMap_2" type="Emp">
     <id property="id" column="id"></id>
     <result property="user_id" column="user_id"></result>
     <result property="realname" column="realname"></result>
     <result property="email" column="email"></result>
     <!--通过外键user_id再次发起查询,调用selectUserById获得User对象-->
     <association property="user" column="user_id" select="selectUserById"></association>
     </resultMap>
    
     <!--根据用户编号获得用户对象-->
     <select id="selectUserById" resultType="User">
     SELECT
     `user`.id,
     `user`.username,
     `user`.`password`
     FROM
     `user` where id=#{id}
     </select>

    测试:

     /**
     * Method: getEmpById_2(int id)
     * 获得员工通过员工编号,一对一方法二
     */
     @Test
     public void testGetEmpById_2() throws Exception {
     Emp entity=empDao.getEmpById_2(2);
     System.out.println(entity);
     Assert.assertNotNull(entity);
     }

    结果:

     

    MyBatis中使用association标签来解决一对一的关联查询,association标签可用的属性如下:

    • property:对象属性的名称
    • javaType:对象属性的类型
    • column:所对应的外键字段名称
    • select:使用另一个查询封装的结果

    1.2、一对多关系

    1.2.1、执行环境

    一个用户帐号可以被多个员工使用,形成一个一对多的关系,表中的数据如下:

    员工表emp:

    用户表user:

    1.2.2、关联查询(1次查询)

    实体:

      员工:

    package com.zhangguo.mybatis03.entities;
    
    /**员工POJO*/
    public class Emp {
     private int id;
     /**用户编号*/
     private int user_id;
     private String realname;
     private String email;
    
     /**用户对象*/
     private User user;
    
     public int getId() {
     return id;
     }
    
     public void setId(int id) {
     this.id = id;
     }
    
     public int getUser_id() {
     return user_id;
     }
    
     public void setUser_id(int user_id) {
     this.user_id = user_id;
     }
    
     public String getRealname() {
     return realname;
     }
    
     public void setRealname(String realname) {
     this.realname = realname;
     }
    
     public String getEmail() {
     return email;
     }
    
     public void setEmail(String email) {
     this.email = email;
     }
    
     public User getUser() {
     return user;
     }
    
     public Emp setUser(User user) {
     this.user = user;
     return this;
     }
    
     @Override
     public String toString() {
     return "Emp{" +
     "id=" + id +
     ", user_id=" + user_id +
     ", realname='" + realname + '\'' +
     ", email='" + email + '\'' +
     ", user=" + user +
     '}';
     }
    }

      用户:

    package com.zhangguo.mybatis03.entities;
    
    import java.util.List;
    
    /**用户POJO*/
    public class User {
     private int id;
     private String username;
     private String password;
    
     /**员工集合,一个用户对象对应多个员工对象*/
     private List<Emp> emps;
    
     public int getId() {
     return id;
     }
    
     public void setId(int id) {
     this.id = id;
     }
    
     public String getUsername() {
     return username;
     }
    
     public void setUsername(String username) {
     this.username = username;
     }
    
     public String getPassword() {
     return password;
     }
    
     public void setPassword(String password) {
     this.password = password;
     }
    
     public List<Emp> getEmps() {
     return emps;
     }
    
     public User setEmps(List<Emp> emps) {
     this.emps = emps;
     return this;
     }
    
     @Override
     public String toString() {
     return "User{" +
     "id=" + id +
     ", username='" + username + '\'' +
     ", password='" + password + '\'' +
     ", emps=" + emps +
     '}';
     }
    }

    接口:

     /**获得用户通过用户编号,1对多级联查询*/
     User getUserById_1(int id);

    映射:

     <!--一对多查询,方法1,通过内联接-->
     <select id="getUserById_1" resultMap="userMap_1" parameterType="int">
     SELECT
     emp.id,
     emp.user_id,
     emp.realname,
     emp.email,
     `user`.username,
     `user`.`password`
     FROM
     emp
     INNER JOIN `user` ON emp.user_id = `user`.id
     where `user`.id=#{id}
     </select>
    
     <resultMap id="userMap_1" type="User">
     <id property="id" column="user_id"></id>
     <result property="username" column="username"></result>
     <result property="password" column="password"></result>
    <!--将emps对象映射成一个集合,emps是user类型中的属性,ofType用于指定集合中存放的对象类型-->
     <collection property="emps" ofType="Emp">
     <id property="id" column="id"></id>
     <result property="user_id" column="user_id"></result>
     <result property="realname" column="realname"></result>
     <result property="email" column="email"></result>
     </collection>
     </resultMap>

     

    测试:

     /**
     * Method: getUserById_1(int id)
     * 获得用户过用户编号,级联查询
     */
     @Test
     public void testGetUserById_1() throws Exception {
     User entity=empDao.getUserById_1(2);
     System.out.println(entity);
     Assert.assertNotNull(entity);
     }

    结果:

    上面的示例中会发现User对象中包含多个Emp对象,此时的Emp对象中又引用了User对象,但值是空的,如果想设置值可以继续用1对1的办法赋值:

    映射:

     <resultMap id="userMap_1" type="User">
     <id property="id" column="user_id"></id>
     <result property="username" column="username"></result>
     <result property="password" column="password"></result>
     <!--将emps对象映射成一个集合,emps是user类型中的属性,ofType用于指定集合中存放的对象类型-->
     <collection property="emps" ofType="Emp">
     <id property="id" column="id"></id>
     <result property="user_id" column="user_id"></result>
     <result property="realname" column="realname"></result>
     <result property="email" column="email"></result>
     <!--映射关系,指定属性与属性的类型-->
     <association property="user" javaType="User">
     <id property="id" column="user_id"></id>
     <result property="username" column="username"></result>
     <result property="password" column="password"></result>
     </association>
     </collection>
     </resultMap>

     

    结果:

    1.1.3、嵌套查询(多次查询)

    实体:同上

    接口:

     /**获得用户通过用户编号,1对多嵌套查询*/
     User getUserById_2(int id);

    映射:

     <!--一对多查询,方法2,通过嵌套查询多次-->
     <select id="getUserById_2" resultMap="userMap_2" parameterType="int">
     SELECT
     `user`.id,
     `user`.username,
     `user`.`password`
     FROM
     `user` where id=#{id}
     </select>
    
     <resultMap id="userMap_2" type="User">
     <id property="id" column="user_id"></id>
     <result property="username" column="username"></result>
     <result property="password" column="password"></result>
     <!--将emps对象映射成一个集合,emps是user类型中的属性,ofType用于指定集合中存放的对象类型-->
     <!--select用于指定再次查询的SQL编号,column用于指定参数列-->
     <collection property="emps" ofType="Emp" column="id" select="selectEmpById"></collection>
     </resultMap>
    
     <!--根据员工编号获得员工对象-->
     <select id="selectEmpById" resultType="Emp">
     SELECT
     emp.id,
     emp.user_id,
     emp.realname,
     emp.email
     FROM
     emp where user_id=#{id}
     </select>

    测试:

     /**
     * Method: getUserById_2(int id)
     * 获得用户过用户编号,嵌套查询
     */
     @Test
     public void testGetUserById_2() throws Exception {
     User entity=empDao.getUserById_2(5);
     System.out.println(entity);
     Assert.assertNotNull(entity);
     }

    结果:

     

    MyBatis中使用collection标签来解决一对多的关联查询,ofType属性指定集合中元素的对象类型。

    二、动态SQL

    2.0、MySQL环境与前置要求

    数据与SQL环境如下:

    前置要求:

    2.1、什么是动态SQL

    MyBatis的动态SQL是基于OGNL的表达式的。它对SQL语句进行灵活的操作,通过表达式判断来实现对SQL的灵活拼接、组装。

     mybatis核心对sql语句进行灵活操作,通过表达式进行判断,对sql进行灵活拼接、组装。

     主要通过以下标签:if,where,choose(when,otherwise),trim,set,foreach。

    2.2、if条件判断

    根据 name和 sex 来查询数据。如果name为空,那么将只根据sex来查询;反之只根据name来查询

    首先不使用 动态SQL 来书写

    接口:

        /**
         * 根据学生姓名和性别获得学生集合
         */
        List<Student> selectStudentsByNameAndSex(@Param("name") String name,@Param("sex") String sex);

    映射:

        <select id="selectStudentsByNameAndSex" resultType="student">
            SELECT id,name,sex from student where name=#{name} and sex=#{sex};
        </select>

    测试:

        /**
         * Method: selectStudentsByNameAndSex
         */
        @Test
        public void testSelectStudentsByNameAndSex() throws Exception {
            List<Student> students=dao.selectStudentsByNameAndSex("rose",null);
            System.out.println(students);
            Assert.assertNotNull(students);
        }

    结果:

     

    上面的查询语句,我们发现如果 #{sex} 为空,那么查询结果也是空,如何解决这个问题呢?使用 if 来判断

        <select id="selectStudentsByNameAndSex" resultType="student">
    
            SELECT id,name,sex from student where 1=1
            <!--如果test为真会输出中间的内容-->
            <if test="name!=null and name!=''">
                and name=#{name}
            </if>
    
            <if test="sex!=null and sex!=''">
                and sex=#{sex}
            </if>
    
        </select>

    结果:

    参考:

    <!-- 2 if(判断参数) - 将实体类不为空的属性作为where条件 --> 
    <select id="getStudentList_if" resultMap="resultMap_studentEntity" parameterType="liming.student.manager.data.model.StudentEntity"> 
     SELECT ST.STUDENT_ID, 
     ST.STUDENT_NAME, 
     ST.STUDENT_SEX, 
     ST.STUDENT_BIRTHDAY, 
     ST.STUDENT_PHOTO, 
     ST.CLASS_ID, 
     ST.PLACE_ID 
     FROM STUDENT_TBL ST 
     WHERE 
     <if test="studentName !=null "> 
     ST.STUDENT_NAME LIKE CONCAT(CONCAT('%', #{studentName, jdbcType=VARCHAR}),'%') 
     </if> 
     <if test="studentSex != null and studentSex != '' "> 
     AND ST.STUDENT_SEX = #{studentSex, jdbcType=INTEGER} 
     </if> 
     <if test="studentBirthday != null "> 
     AND ST.STUDENT_BIRTHDAY = #{studentBirthday, jdbcType=DATE} 
     </if> 
     <if test="classId != null and classId!= '' "> 
     AND ST.CLASS_ID = #{classId, jdbcType=VARCHAR} 
     </if> 
     <if test="classEntity != null and classEntity.classId !=null and classEntity.classId !=' ' "> 
     AND ST.CLASS_ID = #{classEntity.classId, jdbcType=VARCHAR} 
     </if> 
     <if test="placeId != null and placeId != '' "> 
     AND ST.PLACE_ID = #{placeId, jdbcType=VARCHAR} 
     </if> 
     <if test="placeEntity != null and placeEntity.placeId != null and placeEntity.placeId != '' "> 
     AND ST.PLACE_ID = #{placeEntity.placeId, jdbcType=VARCHAR} 
     </if> 
     <if test="studentId != null and studentId != '' "> 
     AND ST.STUDENT_ID = #{studentId, jdbcType=VARCHAR} 
     </if> 
    </select> 

     虽然1=1这种方法结合if可以解决我们的需求,但是1=1明显是冗余的,通过where可以解决。

    2.3、where条件

    where 元素知道只有在一个以上的if条件有值的情况下才去插入“WHERE”子句,若最后的内容是“AND”或“OR”开头的,where 元素也知道如何将他们去除。

    修改后的映射:

        <select id="selectStudentsByNameAndSex" resultType="student">
    
            SELECT id,name,sex from student
    
            <!--1、如果两个if只要有一个有输出就会在sql中添加 where-->
            <where>
                <if test="name!=null and name!=''">
                    <!--2、如果where后以and或or开始则会删除and或or-->
                    and name like concat(concat('%',#{name}),'%');
                </if>
    
                <if test="sex!=null and sex!=''">
                    and sex=#{sex}
                </if>
            </where>
    
        </select>

     

    测试:

        /**
         * Method: selectStudentsByNameAndSex
         */
        @Test
        public void testSelectStudentsByNameAndSex() throws Exception {
            List<Student> students=dao.selectStudentsByNameAndSex("a",null);
            System.out.println(students);
            Assert.assertNotNull(students);
        }

     

     结果:

     

    这个“where”标签会知道如果它包含的标签中有返回值的话,它就插入一个‘where’。此外,如果标签返回的内容是以AND 或OR 开头的,则它会剔除掉。

    where标记的作用类似于动态sql中的set标记,他的作用主要是用来简化sql语句中where条件判断的书写的,如下所示:

      <select id="selectByParams" parameterType="map" resultType="user">
        select * from user
        <where>
          <if test="id != null ">id=#{id}</if>
          <if test="name != null and name.length()>0" >and name=#{name}</if>
          <if test="gender != null and gender.length()>0">and gender = #{gender}</if>
        </where>
      </select>   

    在上述SQL中加入ID的值为null的话,那么打印出来的SQL为:select * from user where name="xx" and gender="xx"

    where 标记会自动将其后第一个条件的and或者是or给忽略掉

    2.4、if+set设置值

    当update语句中没有使用if标签时,如果有一个参数为null,都会导致错误。

    当在update语句中使用if标签时,如果前面的if没有执行,则或导致逗号多余错误。使用set标签可以将动态的配置SET 关键字,和剔除追加到条件末尾的任何不相关的逗号。如果set包含的内容为空的话则会出错。

    使用if+set标签修改后,如果某项为null则不进行更新,而是保持数据库原值。

    如果通过if判断表面可以解决问题,如下所示:

        <update id="updateStudent" parameterType="student">
    
            update student set  
            
            <if test="name!=null and name.lenght()>0">
                name=#{name} ,
            </if>
    
            <if test="sex!=null and sex.lenght()>0">
                sex=#{sex}
            </if>
            
            where id=#{id}
            
        </update>

    这样做也会有问题,就是当sex为空时的sql就变成了 update student set name=#{name} , where id=#{id},这明显是错误的。

    同理,上面的对于查询 SQL 语句包含 where 关键字,如果在进行更新操作的时候,含有 set 关键词,我们怎么处理呢?

    接口:

        /**
         * 更新学生
         */
        int updateStudent(Student entity);

     

    映射:

        <update id="updateStudent" parameterType="student">
            update student
            <!--自动添加set-->
            <set>
                <!--智能处理逗号问题-->
                <if test="name!=null and name.length()>0">
                    name=#{name}
                </if>
    
                <if test="sex!=null and sex.length()>0">
                    sex=#{sex}
                </if>
            </set>
            where id=#{id}
        </update>

    注意:某些情况下逗号必须添加,如下所示:

     

        <update id="updateStudent" parameterType="student">
            update student
            <!--自动添加set-->
            <set>
                <!--智能处理逗号问题-->
                <if test="name!=null and name.length()>0">
                    name=#{name} , 
                </if>
    
                <if test="sex!=null and sex.length()>0">
                    sex=#{sex} , 
                </if>
            </set>
            where id=#{id}
        </update>
    View Code

     

    结尾的逗号会被自动删除。

     

    测试:

        /**
         * Method: updateStudent
         */
        @Test
        public void testUpdateStudent() throws Exception {
            //会将实体中的每一个字段都更新,不好
    //        Student entity=dao.selectStudentById(11);
    //        //entity.setName("张丽美");
    //        entity.setSex("girl");
    //
    //        Assert.assertEquals(1,dao.updateStudent(entity));
    
            //不需要先执行查询
            Student student=new Student();
            student.setId(9);
            //只更新了name与sex没有关系
            student.setName("malili");
            Assert.assertEquals(1,dao.updateStudent(student));
        }

     

    结果:

    这样写,如果第一个条件 name 为空,那么 sql 语句为:update student set sex=? where id=?

    如果第一个条件不为空,那么 sql 语句为:update student u set name= ? , sex = ? where id=?

    set主要解决了自动添加标签与处理逗号的问题,另外这种更新方法比较以前的全部更新方式在开发中性能更高。

    2.5、choose(when,otherwise) 开关

    如果不想用到所有的查询条件,只想选择其中的一个,查询条件有一个满足即可,使用 choose 标签可以解决此类问题,类似于 Java 的 switch 语句。

    假定这里需要优先根据编号搜索,没有时选择name,最后考虑sex:

    接口:

        /**
         * 根据学生编号、姓名和性别获得学生集合
         */
        List<Student> selectStudentsByNameAndSex(@Param("id") int id, @Param("name") String name,@Param("sex") String sex);

     

    映射:

        <select id="selectStudentsByNameAndSex" resultType="student">
    
            SELECT id,name,sex from student
            <where>
            <choose>
                <when test="id>0">
                    id=#{id}
                </when>
                <when test="name!=null and name!=''">
                    name=#{name}
                </when>
                <otherwise>
                    sex=#{sex}
                </otherwise>
            </choose>
            </where>
        </select>

     

    测试:

        /**
         * Method: selectStudentsByNameAndSex
         */
        @Test
        public void testSelectStudentsByNameAndSex() throws Exception {
            List<Student> students=dao.selectStudentsByNameAndSex(1,"rose","girl");
            System.out.println(students);
            Assert.assertNotNull(students);
        }

     

    结果:

     

    也就是说,这里我们有三个条件,id,name,sex,只能选择一个作为查询条件

    如果 id 不为空,那么查询语句为:select * from student where  id=?

    如果 id 为空,那么看name是否为空,如果不为空,那么语句为 select * from student where  name=?;

    如果name为空,那么查询语句为 select * from student  where sex=?

    2.6、trim裁剪

    trim标记是一个格式化的标记,可以完成set或者是where标记的功能

    ①、用 trim 改写上面第二点的 if+where 语句

    if+where的办法:

        <select id="selectStudentsByNameAndSex" resultType="student">
    
            SELECT id,name,sex from student
    
            <!--1、如果两个if只要有一个有输出就会在sql中添加 where-->
            <where>
                <if test="name!=null and name!=''">
                    <!--2、如果where后以and或or开始则会删除and或or-->
                    and name like concat(concat('%',#{name}),'%');
                </if>
    
                <if test="sex!=null and sex!=''">
                    and sex=#{sex}
                </if>
            </where>
    
        </select>

    trim的办法:

        <select id="selectStudentsByNameAndSex" resultType="student">
    
            SELECT id,name,sex from student
    
            <!--1、prefix表示将前置where,prefixOverrides将删除打头内容-->
            <trim prefix="where" prefixOverrides="and | or">
                <if test="name!=null and name!=''">
                    and name like concat(concat('%',#{name}),'%')
                </if>
    
                <if test="sex!=null and sex!=''">
                    and sex=#{sex}
                </if>
            </trim>
    
        </select>

     

    测试结果:

    prefix:将加上前缀      

    prefixoverride:去掉第一个and或者是or

    ②、用 trim 改写上面第三点的 if+set 语句

    if+set的方法:

        <update id="updateStudent" parameterType="student">
            update student
            <!--自动添加set-->
            <set>
                <!--智能处理逗号问题-->
                <if test="name!=null and name.length()>0">
                    name=#{name}
                </if>
    
                <if test="sex!=null and sex.length()>0">
                    sex=#{sex}
                </if>
            </set>
            where id=#{id}
        </update>

    trim的方法:

        <update id="updateStudent" parameterType="student">
            update student
    
               <trim prefix="set" suffixOverrides=",">
                   <if test="name!=null and name.length()>0">
                       name=#{name},
                   </if>
    
                   <if test="sex!=null and sex.length()>0">
                       sex=#{sex},
                   </if>
               </trim>
    
            where id=#{id}
        </update>

    结果:

    suffix:后缀  

    suffixoverride:去掉最后一个逗号(也可以是其他的标记,就像是上面前缀中的and一样) 

    可以自定义添加前后缀,与之对应的属性是prefix和suffix。同时通过prefixOverrides和suffixOverrides分别来覆盖首尾部的内容,即忽略不必要的前后缀。就是说它可以充当where标签,也可以充当set标签啦~
    充当where标签:

    <trim prefix = "where" prefixOverrides="and|or" >
    ...
    </trim>

    充当set标签:

    <trim prefix="set" suffixOverrides=",">
    ...
    </trim>

    例子:动态添加用户属性

    <insert id="find" resultType="Admin">
    insert into admin 
    <trim prefix="(" suffix=")" suffixOverrides=",">
    <if test = "aname != null and aname !='' ">
    aname,
    </if>
    <if test = "city != null and city !='' ">
    city,
    </if>
    <if test = "age != null and age !='' ">
    age,
    </if>
    </trim>
    <trim prefix="values(" suffix=")" suffixOverrides=",">
    <if test = "aname != null and aname !='' ">
    #{aname},
    </if>
    <if test = "city != null and city !='' ">
    #{city},
    </if>
    <if test = "age != null and age !='' ">
    #{age},
    </if>
    </trim>
    </insert>

    上面相应的语句为:insert into admin (…) values(…);。通过trim标签用()包裹,以及自动忽略尾部的逗号。

    2.7、SQL 片段

    有时候可能某个 sql 语句我们用的特别多,为了增加代码的重用性,简化代码,我们需要将这些代码抽取出来,然后使用时直接调用。

    比如:下面的映射文件中对于id,name,sex出现多次:

        <select id="selectStudentsByNameOrSex" resultType="student">
            SELECT id,name,sex from student where name like '%${realname}%' or sex=#{sex};
        </select>
    
        <select id="selectStudentsByIdOrSex" resultType="student">
            SELECT id,name,sex from student where id=#{no} or sex=#{sex};
        </select>
    
        <select id="selectStudentsByNameAndSex" resultType="student">
    
            SELECT id,name,sex from student
    
            <!--1、prefix表示将前置where,prefixOverrides将删除打头内容-->
            <trim prefix="where" prefixOverrides="and | or">
                <if test="name!=null and name!=''">
                    and name like concat(concat('%',#{name}),'%')
                </if>
    
                <if test="sex!=null and sex!=''">
                    and sex=#{sex}
                </if>
            </trim>
    
        </select>

     

     

    加粗的内容是重复的,通过sql片段复用。

    定义sql片段:

        <!--定义sql片段-->
        <sql id="col_student">
            id,name,sex
        </sql>
        

    引用 sql 片段

        <select id="selectStudentsByNameOrSex" resultType="student">
            <!--引用sql片段-->
            SELECT <include refid="col_student"></include> from student where name like '%${realname}%' or sex=#{sex};
        </select>
    
        <select id="selectStudentsByIdOrSex" resultType="student">
            SELECT <include refid="col_student"></include> from student where id=#{no} or sex=#{sex};
        </select>
    
        <select id="selectStudentsByNameAndSex" resultType="student">
    
            SELECT <include refid="col_student"></include> from student
    
            <!--1、prefix表示将前置where,prefixOverrides将删除打头内容-->
            <trim prefix="where" prefixOverrides="and | or">
                <if test="name!=null and name!=''">
                    and name like concat(concat('%',#{name}),'%')
                </if>
    
                <if test="sex!=null and sex!=''">
                    and sex=#{sex}
                </if>
            </trim>
    
        </select> 

    结果:

    注意:①、最好基于 单表来定义 sql 片段,提高片段的可重用性

       ②、在 sql 片段中不要包括 where 

    sql片段带参数:

    定义时使用参数:

        <!--定义sql片段-->
        <sql id="col_student">
            ${alias}.id,${alias}.name,${alias}.sex
        </sql>

    引用时指定参数:

        <select id="selectStudentsByNameAndSex" resultType="student">
    
            SELECT
    
            <include refid="col_student">
                <property name="alias" value="s"></property>
            </include>
    
            from student s
    
            <!--1、prefix表示将前置where,prefixOverrides将删除打头内容-->
            <trim prefix="where" prefixOverrides="and | or">
                <if test="name!=null and name!=''">
                    and name like concat(concat('%',#{name}),'%')
                </if>
    
                <if test="sex!=null and sex!=''">
                    and sex=#{sex}
                </if>
            </trim>
    
        </select>

    结果:

    2.8、foreach循环

    foreach元素的功能非常强大,它允许你指定一个集合,声明可以在元素体内使用的集合项(item)和索引(index)变量。它也允许你指定开头与结尾的字符串以及在迭代结果之间放置分隔符。这个元素是很智能的,因此它不会偶然地附加多余的分隔符。

    注意 你可以将任何可迭代对象(如 List、Set 等)、Map 对象或者数组对象传递给 foreach 作为集合参数。当使用可迭代对象或者数组时,index 是当前迭代的次数,item 的值是本次迭代获取的元素。当使用 Map 对象(或者 Map.Entry 对象的集合)时,index 是键,item 是值。

    到此我们已经完成了涉及 XML 配置文件和 XML 映射文件的讨论。下一章将详细探讨 Java API,这样就能提高已创建的映射文件的利用效率。

    foreach的主要用在构建in条件中,他可以迭代一个集合。foreach元素的属性主要有:item,index,collection,open,separator,close。

    下面对属性进行简单的介绍:

    item:表示集合中每一个元素进行迭代时的别名。

    index:指定一个名字,用于表示在迭代过程中每次迭代的位置。

    open:表示以什么开始。

    separator:每次迭代以什么分割。

    close:以什么关闭。

    collection:最重要且必须指定的有三种情况:

    1.如果传入的是单独参数的List类型时,collection的属性值为list。

    2.如果传入的是单独参数的数组时,collection的属性值为array。

    3.如果传入多个参数时,我们把多个参数放入map中,单参数也可以放入map中。map中的key就是参数名,所以collection属性值就是传入的List或者array对象在Map里的key。 

    一、用 foreach 来改写 select * from user where id=1 or id=2 or id=3

    <select id="selectUserByListId" parameterType="com.ys.vo.UserVo" resultType="com.zhangguo.User">
     select * from user
     <where>
     <!--
     collection:指定输入对象中的集合属性
     item:每次遍历生成的对象
     open:开始遍历时的拼接字符串
     close:结束时拼接的字符串
     separator:遍历对象之间需要拼接的字符串
     select * from user where 1=1 and (id=1 or id=2 or id=3)
     -->
     <foreach collection="ids" item="id" open="and (" close=")" separator="or">
     id=#{id}
     </foreach>
     </where>
    </select>

    二、我们用 foreach 来改写 select * from user where id in (1,2,3)

    <select id="selectUserByListId" parameterType="com.ys.vo.UserVo" resultType="com.zhangguo.User">
     select * from user
     <where>
     <!--
     collection:指定输入对象中的集合属性
     item:每次遍历生成的对象
     open:开始遍历时的拼接字符串
     close:结束时拼接的字符串
     separator:遍历对象之间需要拼接的字符串
     select * from user where 1=1 and id in (1,2,3)
     -->
     <foreach collection="ids" item="id" open="and id in (" close=") " separator=",">
     #{id}
     </foreach>
     </where>
     </select> 

    其实动态 sql 语句的编写往往就是一个拼接的问题,为了保证拼接准确,我们最好首先要写原生的 sql 语句出来,然后在通过 mybatis 动态sql 对照着改。

    参考:

    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE mapper
    PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
    "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    
    <!-- namespace的名字需要跟接口的类名一致 -->
    <mapper namespace="cn.bdqn.dao.UserMapper">
     <!-- 
     1、resultMap属性:type为java实体类;id为此resultMap的标识
     2、resultMap的子元素:
     id – 一般对应到数据库中该行的ID,设置此项可以提高Mybatis性能.
     result – 映射到JavaBean 的某个“简单类型”属性,String,int等.
     association – 映射到JavaBean 的某个“复杂类型”属性,其他JavaBean类.
     collection –复杂类型集合 
     -->
     
     <!--根据roleId获取用户列表: 当数据库中的字段信息与对象的属性不一致时需要通过resultMap来映射 -->
     <!-- <resultMap type="User" id="seachUserResult">
     <result property="id" column="id"/>
     <result property="userCode" column="userCode"/>
     <result property="userName" column="userName"/>
     <result property="roleId" column="roleId"/>
     <result property="roleName" column="roleName"/>
     </resultMap>
     
     <select id="getUserListByRoleId" parameterType="Role" resultMap="seachUserResult">
     select u.*,r.roleName as roleName from user u,role r where u.roleId = r.id and u.roleId = #{id}
     </select> -->
     
     <!-- 根据roleId获取用户列表 association start-->
     <resultMap type="User" id="seachUserResult">
     <result property="id" column="id"/>
     <result property="userCode" column="userCode" />
     <result property="userName" column="userName" />
     <result property="roleId" column="roleId" />
     <!-- <association property="role" javaType="Role" >
     <result property="id" column="id"/>
     <result property="roleCode" column="roleCode"/>
     <result property="roleName" column="roleName"/>
     </association> -->
     <association property="role" javaType="Role" resultMap="roleMap"/>
     </resultMap>
     
     <resultMap type="Role" id="roleMap">
     <result property="id" column="id"/> 
     <result property="roleCode" column="roleCode"/> 
     <result property="roleName" column="roleName"/> 
     </resultMap>
     
     <select id="getUserListByRoleId" parameterType="Role" resultMap="seachUserResult">
     select u.*,r.roleCode as roleCode,r.roleName as roleName from user u,role r where u.roleId = r.id and u.roleId = #{id}
     </select>
     
     <!-- association end-->
     
     <!-- 获取指定用户的地址列表(user表-address表:1对多关系) collection start-->
     <resultMap type="User" id="userMap">
     <id property="id" column="userId"/>
     <collection property="addressList" ofType="Address">
     <id property="id" column="a_id"/>
     <result property="postCode" column="postCode"/>
     <result property="addressContent" column="addressContent"/>
     </collection>
     </resultMap>
     
     <select id="getAddressListByUserId" parameterType="User" resultMap="userMap">
     select *,a.id as a_id from user u,address a where u.id=a.userId and u.id=#{id}
     </select>
     <!-- collection end -->
     
     <resultMap type="User" id="seachUser">
     <result property="id" column="id"/>
     <result property="userCode" column="userCode"/>
     <result property="userName" column="userName"/>
     <result property="roleId" column="roleId"/>
     <result property="roleName" column="roleName"/>
     </resultMap>
     
     <!-- <select id="searchUserList" parameterType="User" resultMap="seachUser">
     select u.*,r.roleName as roleName from user u,role r where u.roleId = r.id
     and u.roleId = #{roleId}
     and u.userCode like CONCAT ('%',#{userCode},'%') //防止sql注入
     and u.userName like CONCAT ('%',#{userName},'%') 
     </select> -->
     
     <!-- 
     1、有些时候,sql语句where条件中,需要一些安全判断,例如按性别检索,如果传入的参数是空的,此时查询出的结果很可能是空的,也许我们需要参数为空时,是查出全部的信息。这是我们可以使用动态sql,增加一个判断,当参数不符合要求的时候,我们可以不去判断此查询条件。
     2、mybatis 的动态sql语句是基于OGNL表达式的。可以方便的在 sql 语句中实现某些逻辑. 总体说来mybatis 动态SQL 语句主要有以下几类: 
     if 语句 (简单的条件判断) 
     choose (when,otherwize) ,相当于java 语言中的 switch ,与 jstl 中的choose 很类似.
     trim (对包含的内容加上 prefix,或者 suffix 等,前缀,后缀) 
     where (主要是用来简化sql语句中where条件判断的,能智能的处理 and or ,不必担心多余导致语法错误) 
     set (主要用于更新时) 
     foreach (在实现 mybatis in 语句查询时特别有用) 
     -->
     
     <!-- if(判断参数) - 将实体类不为空的属性作为where条件 -->
     <select id="searchUserList" parameterType="User" resultMap="seachUser">
     select u.*,r.roleName as roleName from user u,role r where u.roleId = r.id
     <if test="roleId!=null">
     and u.roleId = #{roleId}
     </if>
     <if test="userCode != null">
     and u.userCode like CONCAT ('%',#{userCode},'%') 
     </if>
     <if test="userName != null">
     and u.userName like CONCAT ('%',#{userName},'%') 
     </if>
     </select>
     
     
     
     
     
     <select id="count" resultType="int">
     select count(1) from user
     </select>
     
     <insert id="add" parameterType="User">
     insert into user (userCode,userName,userPassword) 
     values (#{userCode},#{userName},#{userPassword})
     </insert>
     
     <!-- if/set(判断参数) - 将实体类不为空的属性更新 --> 
     <!-- <update id="update" parameterType="User">
     update user 
     <set>
     <if test="userCode != null and userCode != ''">userCode=#{userCode},</if>
     <if test="userName != null">userName=#{userName},</if>
     <if test="userPassword != null">userPassword=#{userPassword},</if>
     <if test="roleId != null">roleId=#{roleId}</if>
     </set>
     where id=#{id}
     </update> -->
     
     <!-- if/trim代替set(判断参数) - 将实体类不为空的属性更新 --> 
     <update id="update" parameterType="User">
     update user 
     <trim prefix="set" suffixOverrides=",">
     <if test="userCode != null and userCode != ''">userCode=#{userCode},</if>
     <if test="userName != null">userName=#{userName},</if>
     <if test="userPassword != null">userPassword=#{userPassword},</if>
     <if test="roleId != null">roleId=#{roleId}</if>
     </trim>
     where id=#{id}
     </update>
     
     <!--注意: 你可以传递一个List实例或者数组作为参数对象传给MyBatis。
     当你这么做的时候,MyBatis会自动将它包装在一个Map中,用名称在作为键。
     List实例将会以“list”作为键,而数组实例将会以“array”作为键。
     配置文件中的parameterType是可以不配置的-->
     <resultMap type="User" id="userMapByDep">
     <result property="id" column="id"/>
     <result property="userCode" column="userCode"/>
     <result property="userName" column="userName"/>
     </resultMap>
     <!-- foreach(循环array参数) - 作为where中in的条件 -->
     <select id="getUserByDepId_foreach_array" resultMap="userMapByDep">
     select * from user where depId in 
     <foreach collection="array" item="depIds" open="(" separator="," close=")">
     #{depIds}
     </foreach>
     </select>
     
     <!-- foreach(循环List<String>参数) - 作为where中in的条件 -->
     <select id="getUserByDepId_foreach_list" resultMap="userMapByDep">
     select * from user where depId in 
     <foreach collection="list" item="depIdList" open="(" separator="," close=")">
     #{depIdList}
     </foreach>
     </select>
     
     
     <delete id="delete" parameterType="User">
     delete from user where id=#{id}
     </delete>
     
     <select id="getUserList" resultType="User">
     select * from user
     </select>
    </mapper>
    View Code

    假定我们要多删除:

    接口:

        /**
         * 删除多个学生通过编号
         */
        int deleteStudents(List<Integer> ids);

     

    映射:

        <delete id="deleteStudents">
            delete from student where id in
            <foreach collection="list" item="id" open="(" separator="," close=")">
                #{id}
            </foreach>
        </delete>

     

    注意collection这里只能是list,不能是ids,因为反射时获取不到参数名称。

    测试:

     

        /**
         * Method: deleteStudents
         */
        @Test
        public void testDeleteStudents() throws Exception {
            List<Integer> ids=new ArrayList<Integer>();
            ids.add(8);
            ids.add(9);
            Assert.assertEquals(2,dao.deleteStudents(ids));
        }

     

    结果:

     

    2.9、bind 绑定变量

    bind标签可以使用OGNL表达式创建一个变量并将其绑定到上下文中。

    bind标签的两个属性都是不选项,name为绑定到上下文的变量名,value为OGNL表达式,创建一个bind标签后,就可以在下面直接使用了。 使用bind拼接字符串不仅可以避免因更换数据库而修改SQL,也能预防SQL注入。

          <!-- List<Employee> getEmpsTestInnerParameter(Employee employee); -->
          <select id="getEmpsTestInnerParameter" resultType="com.hand.mybatis.bean.Employee">
              <!-- bind:可以将OGNL表达式的值绑定到一个变量中,方便后来引用这个变量的值 -->
              <bind name="bindeName" value="'%'+eName+'%'"/> eName是employee中一个属性值
              SELECT * FROM emp 
              <if test="_parameter!=null">
                where ename like #{bindeName}
              </if>
          </select>

     

    三、视频

     https://www.bilibili.com/video/av32447485/

    四、示例

    https://git.coding.net/zhangguo5/MyBatis03.git

    五、作业

    1、个人项目的数据库设计,个人项目的静态页面设计(2个,一个必须是首页,PC端)

    2、重现本章示例

    3、任务指导手册所有mybatis理论题

    4、根据如下ER图创建4个表,完成1-1,1-N,M-N关系的查询,无需界面,测试通过即可

    5、完成图书管理系统中二表关联,显示图书类型

    请实现一个简易图书管理系统(LibSystem),实现图书管理功能,要求如下:
    1、管理数据库中所有图书(Books),包含图书编号(isbn)、书名(title)、作者(author)、价格(price)、出版日期(publishDate)
    2、Maven多模块+MySQL+Git+MyBatis+JUnit单元测试
    3、表示层可以是AJAX或JSTL
    
    请实现一个迷你图书管理系统(LibSystem),实现图书管理功能,要求如下:
    1、管理数据库中所有图书分类(Categories),包含图书编号(id),名称(name)
    2、管理数据库中所有图书(Books),包含图书编号(isbn)、类别(categoryId,外键)书名(title)、作者(author)、价格(price)、出版日期(publishDate)、封面(cover)、详细介绍(details)
    3、分页
    4、多条件组件查询(3个以上的条件)
    5、上传封面
    6、富文本编辑器
    View Code

     

    6、使用任意的原型开发工具设计出个人项目的1-2个界面,工具:Balsamiq Mockups,Axure RP Pro 7.0。

    7、将动态sql中的所有知识点全部应用于作业4

     

    展开全文
  • 在该示例中,我们将展示利用SQL语句的动态生成实现 数据的解构,并将数据分解插入到数据库中。在该示例中,我们利用给定数据(类excel)去初始化数据库。数据的各项信息存储在数据库的不同表格里。在该示例中...

    T-SQL 中的SQl语句动态生成是一个强有力的工具,他能够实现在运行时才能决定SQL语句的生成与执行。在该示例中,我们将展示利用SQL语句的动态生成实现 数据表的解构,并将数据分解插入到数据库中。

    在该示例中,我们利用给定数据表(类excel)去初始化数据库。数据表的各项信息存储在数据库的不同表格里。在该示例中我们需要初始化 特定部门、特定子职位的员工数。

    GO
    
    CREATE TABLE #SubPositionBreakDown (
        NAME VARCHAR(50)
        ,D1 INT
        ,D2 INT
        ,D3 INT
        ,D4 INT
        ,D5 INT
        ,D6 INT
        ,D7 INT
        );
    -- 初始化数据表,可以利用Excel公式生成。
    INSERT INTO #SubPositionBreakDown VALUES
    ('SubPosition1', NULL, NULL, 10, 25, 48, 4, 50),
    ('SubPosition2', NULL, 25, NULL, NULL, NULL, NULL, NULL),
    ('SubPosition3', NULL,  25, 85, 59, 33, 2, 8),
    ('SubPosition4', NULL, NULL, 5, 5, 5, 5, 3),
    ('SubPosition5', NULL, NULL, NULL, NULL, NULL, NULL, NULL),
    ('SubPosition6', NULL, NULL, NULL, 10, 13, 2, 35),
    ('SubPosition7', NULL, 25, NULL, NULL, NULL, NULL, NULL),
    ('SubPosition8', 100, 25, NULL, NULL, NULL, NULL, NULL);
    
    DECLARE @DepartmentMappings TABLE (
        DepartmentName VARCHAR(50)
        ,MapName VARCHAR(50)
        );
    --将数据表的部门信息 映射到数据库的部门信息
    INSERT INTO @DepartmentMappings VALUES
    ('Department1', 'D1'),
    ('Department2', 'D2'),
    ('Department3', 'D3'),
    ('Department4', 'D4'),
    ('Department5', 'D5'),
    ('Department6', 'D6'),
    ('Department7', 'D7');
    
    --利用游标来生成 职位-部门,映射数据。
    DECLARE cur CURSOR
    FOR
    SELECT MP.DepartmentID
        ,SP.Id AS SubPositionId
        ,SP.NAME
        ,DM.MapName
    FROM #SubPositionBreakDown SB
    INNER JOIN dbo.SubPositions SP ON SB.NAME = SP.NAME
    CROSS JOIN @DepartmentMappings DM
    
    INNER JOIN dbo.Departments D ON D.DepartmentName = DM.DepartmentName
    
    DECLARE @DepartmentId INT;
    DECLARE @SubPositionId INT;
    DECLARE @SubPositionName VARCHAR(50);
    DECLARE @MapName VARCHAR(50);
    DECLARE @tempValue DECIMAL;
    
    OPEN cur;
    
    FETCH NEXT
    FROM cur
    INTO @DepartmentId
        ,@SubPositionId
        ,@SubPositionName
        ,@MapName;
    
    WHILE (@@FETCH_STATUS = 0)
    BEGIN
        DECLARE @sql NVARCHAR(200);
        --动态生成的SQl 语句
        SET @sql = 'SELECT @tempValue=' + QUOTENAME(@MapName) + ' FROM ' + QUOTENAME('#SubPositionBreakDown') + ' WHERE Name=''' + CAST(@SubPositionName AS CHAR(50)) + '''';
        --执行该动态生成的语句
        EXEC sp_executesql @sql
            ,N'@tempValue INT OUTPUT'
            ,@tempValue OUTPUT
    
        IF (@tempValue IS NOT NULL)
        BEGIN
            IF NOT EXISTS (
                    SELECT 1
                    FROM dbo.SubPositionbreakdown
                    WHERE DepartmentId = @DepartmentId
                        AND SubPositionId = @SubPositionId
                    )
            BEGIN
                INSERT INTO dbo.SubPositionbreakdown (
                    DepartmentID
                    ,SubPositionId
                    ,Weighting
                    ,DateCreated
                    )
                VALUES (
                    @DepartmentId
                    ,@SubPositionId
                    ,@tempValue
                    ,GETDATE()
                    );
            END
        END
    
        FETCH NEXT
        FROM cur
        INTO @DepartmentId
            ,@SubPositionId
            ,@SubPositionName
            ,@MapName;
    END
    
    CLOSE cur;
    DEALLOCATE cur;
    DROP TABLE #SubPositionBreakDown;
    
    GO
    展开全文
  • 实例:员工信息Word文件,程序动态替换内容,生成pdf文件 话不多说,先看效果图! 优势: 1、模板只是布局调整,程序无需修改! 2、以往做法,写成HTML 页面方便替换内容,再生成word,这样做存在错位兼容...

    Word模板文件,替换内容 文本、图片、表格、列表、区块、嵌套等

    实例:员工信息表Word文件,程序动态替换内容,生成pdf文件

     话不多说,先看效果图!

    优势:

    1、模板只是布局调整,程序无需修改! 

    2、以往做法,写成HTML 页面方便替换内容,再生成word,这样做存在错位兼容问题! 

     

    直接贴代码:

    第一步:pom.xml

        <dependency>
                <groupId>com.deepoove</groupId>
                <artifactId>poi-tl</artifactId>
                <version>1.7.3</version>
            </dependency>

    官方文档地址:http://deepoove.com/poi-tl/#_%E6%96%87%E6%9C%AC

    第二步:实例代码

    package cn.com.poi;
    
    
    import com.deepoove.poi.XWPFTemplate;
    import com.deepoove.poi.config.Configure;
    import com.deepoove.poi.data.PictureRenderData;
    import com.deepoove.poi.policy.HackLoopTableRenderPolicy;
    import com.deepoove.poi.util.BytePictureUtils;
    import org.junit.Test;
    
    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.util.ArrayList;
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;
    
    
    public class word {
    
    
        @Test
        public void test() throws IOException {
    
            String fie = "D:\\员工信息登记表.docx";
            String output = "D:\\output.docx";
    
            Map<String, Object> userInfo = new HashMap<>();
            userInfo.put("name", "刘**");
            userInfo.put("sex", "男");
            userInfo.put("age", "30岁");
            userInfo.put("birth", "1990年");
            userInfo.put("en_name", "Saimen");
            userInfo.put("country", "中国");
            userInfo.put("province", "广东");
            userInfo.put("city", "深圳");
            userInfo.put("nation", "汉族");
            userInfo.put("telephone", "137******3");
            userInfo.put("email", "326427540@qq.com");
            userInfo.put("hobby", "TV 电视 电影 代码");
            userInfo.put("body", "健康");
            userInfo.put("political", "☐群众 ☐团员 ☐预备党员 ☐党员 ☑其他");
    
            userInfo.put("xz_province", "广东");
            userInfo.put("xz_city", "深圳");
            userInfo.put("xz_area", "宝安");
            userInfo.put("xz_adder", "西乡街道办");
    
            userInfo.put("yj_province", "江西");
            userInfo.put("yj_city", "九江");
            userInfo.put("yj_area", "鄱阳湖");
            userInfo.put("yj_adder", "鄱阳湖水边");
    
            userInfo.put("hk_province", "广东");
            userInfo.put("hk_city", "深圳");
            userInfo.put("hk_nature", "☐农村户口 ☑城镇户口");
    
            userInfo.put("id_card_type", "身份证");
            userInfo.put("id_card_number", "363************X");
            userInfo.put("bank_name", "平安银行");
            userInfo.put("bank_number", "378************1");
    
            userInfo.put("marriage", "☐未婚(☐单身  ☐非单身)☑已婚 ☐离异 ☐丧偶");
            userInfo.put("childbirth", "☐未生育 ☐已育1孩 ☑已育2孩  ☐已育2孩以上");
            userInfo.put("english_ability", "英语超级好");
            userInfo.put("other_ability", "计算机语言");
            userInfo.put("computer_grade", "四级");
            userInfo.put("titles_type", "首席技术官");
            userInfo.put("titles_level", "AAAAA级");
            userInfo.put("social_security_no", "66666");
            userInfo.put("accumulation_fund_no", "999999");
            // 网络图片
            userInfo.put("image", new PictureRenderData(92, 120, ".jpg",
                    BytePictureUtils.getUrlBufferedImage("https://avatar.csdnimg.cn/4/9/F/1_qq_15371293_1593430328.jpg")
            ));
            //统招
            HashMap<String, Object> t_school_map = new HashMap<String, Object>() {{
                put("from_start_date", "2020/07/03");
                put("from_end_date", "2020/07/05");
                put("school", "**大学");
                put("specialty", "***专业");
                put("education", "本科");
                put("graduation_type", "统招");
                put("if_max", "☑是 ☐否");
            }};
            List<Object> t_school = new ArrayList<>();
            t_school.add(t_school_map);
            userInfo.put("t_school", t_school);
            //非统招
            HashMap<String, Object> ft_school_map = new HashMap<String, Object>() {{
                put("from_start_date", "1993/07/03");
                put("from_end_date", "1995/07/05");
                put("school", "爱心幼儿园");
                put("specialty", "大班");
                put("education", "幼儿园");
                put("graduation_type", "非统招");
                put("if_max", "☑是 ☐否");
            }};
            List<Object> ft_school = new ArrayList<>();
            ft_school.add(ft_school_map);
            userInfo.put("ft_school", ft_school);
            //工作信息
            HashMap<String, Object> work_map = new HashMap<String, Object>() {{
                put("from_start_date", "1993/07/03");
                put("from_end_date", "1995/07/05");
                put("where_work", "A公司");
                put("work_department", "研发中心");
                put("job_name", "首席技术官");
                put("superiors", "老板");
                put("telephone", "13760330153");
            }};
            List<Object> work = new ArrayList<>();
            work.add(work_map);
            userInfo.put("work", work);
            //培训经验
            HashMap<String, Object> train_map = new HashMap<String, Object>() {{
                put("from_start_date", "2020/07/3");
                put("from_end_date", "2020/07/05");
                put("training_program", "无");
                put("training_agency_name", "无");
                put("certificate", "无");
            }};
            List<Object> train = new ArrayList<>();
            train.add(train_map);
            userInfo.put("train", train);
            //资格证书获得情况
            HashMap<String, Object> qualification_map = new HashMap<String, Object>() {{
                put("certificate_name", "英语6级");
                put("giver_unit", "英语机构");
                put("certificate_date", "2001-02-06");
                put("effective_date", "永久");
    
            }};
            List<Object> qualification = new ArrayList<>();
            qualification.add(qualification_map);
            userInfo.put("qualification", qualification);
            //family
            HashMap<String, Object> family_map = new HashMap<String, Object>() {{
                put("family_relationship", "父亲");
                put("family_name", "刘**");
                put("family_workplace", "大自然");
                put("occupation", "五谷杂粮");
                put("telephone", "13******");
                put("is_sos", "\uF052☑是 ☐否");
            }};
            List<Object> family = new ArrayList<>();
            family.add(family_map);
            userInfo.put("family", family);
    
    
            HackLoopTableRenderPolicy policy = new HackLoopTableRenderPolicy();
            Configure config = Configure.newBuilder()
                    .bind("t_school", policy)
                    .bind("ft_school", policy)
                    .bind("work", policy)
                    .bind("train", policy)
                    .bind("qualification", policy)
                    .bind("family", policy)
                    .build();
    
    
            XWPFTemplate template = XWPFTemplate.compile(fie, config).render(userInfo);
            FileOutputStream out = new FileOutputStream(output);
            template.write(out);
            out.flush();
            out.close();
            template.close();
        }
    
    
    }
    

    第三步:下载演示文件    http://note.youdao.com/s/TnLKuWGq

    为 deepoove 点赞 

    展开全文
  • 可慧内容管理系统

    2008-05-07 09:18:28
    这就是说,只要会用浏览器,您的员工就能正确地管理KehuiCMS系统。 内嵌的 所见即所得 的内容编辑器。 可定制的模板引擎,可最大化地定制网站的界面布局,多模版支持,用户可以自由选择自己喜欢的界面。 ...
  • EXCEL办公室专用表格

    2014-03-07 11:06:50
    人事动态及费用资料.zip 人事管理制度样例.zip 人事部年度招聘报批.zip 人员增补申请.zip 人员试用标准.zip 休假制度.zip 会议管理规定.zip 保密制度.zip 公司劳动工资结构.zip 公司奖励种类一览.zip 公司...
  • 成功实施ERP,必须重视培训,而培训绝不仅仅是单纯系统操作的培训,从项目的实施开始到后期,相应的培训都是贯穿始终的,分阶段、分内容、分人员、分管里层次地分别进行系统的培训。培训还必须要有完整的培训知识库...
  • 工作内容调查日报.doc 工作说明书.doc 公司部门中层领导年度工作考核.doc 公司工资制度方案.doc 公司纪律规定.doc 公司奖励种类一览.doc 公司劳动工资结构.doc 管理才能考核.doc 管理人才储备.doc...
  • 人事管理系统(php)

    2009-07-03 09:22:58
    小学期用了5天时间自己完成的一个数据库操作实验内容,内有用户登陆系统,面向两类用户(管理员 ,普通员工 ),管理员可以添加员工,修改员工信息,删除员工信息,按编号,姓名或高级查询员工信息,员工动态性别,婚姻状况,职称...
  • 作者:Irain QQ:2573396010 微信:18802080892 ...MySQL5.1版本出现的新特性,通过表动态生成的数据 2 创建视图 语法:create view 视图名 as 查询语句; 2.1 创建有员工名和其部门名的视图 drop vi...
  • 菜鸟进击__003__12.12

    2019-12-12 22:30:13
    员工信息的建立与迭代: 1.静态页面的铺设 运用bootstrap栅格系统布局出基本结构,CSS样式改变,实现页面内容 2.动态行为的建立 表单input提交;表单验证实现;信息提交到制定地点(未实现);信息获取并输出(未...
  • 工作内容调查日报.doc 52,738 05-01-01 09:11 -a-- 工作说明书.doc 30,210 05-01-01 09:11 -a-- 公司工资制度方案.doc 25,602 04-02-20 10:56 -a-- 公司纪律规定.doc 19,458 05-01-01 09:11 -a-- 公司奖励种类一览...
  • 197 根据员工的各项考核成绩判断员工是否合格 381 198 判断员工是否需要补考 382 199 判断员工是否缺考 383 200 查询员工是否享受夜班补贴 385 201 计算员工12月工资 387 202 汇总商品的销售额 388 203...
  • 很多人在开发中遇到过这样的问题:一个,有自己编号,内容,上级编号,如何用这些数据在jsp中构造一个树?做树并不复杂,但我们通常做的是2层或3层,那样的数据一般来自多个,比如:部门,员工然而这种自连接的...
  • 实例083 实现跨数据库的表内容复制 实例084 使用UNION ALL语句批量插入数据 实例085 更新指定记录 实例086 将数据表清空 第4章 SQL语句应用技术 4.1 聚集函数与日期查询 实例087 利用SUM函数实现数据汇总 实例088 ...
  • 实例083 实现跨数据库的表内容复制 实例084 使用UNION ALL语句批量插入数据 实例085 更新指定记录 实例086 将数据表清空 第4章 SQL语句应用技术 4.1 聚集函数与日期查询 实例087 利用SUM函数实现数据汇总 实例088 ...
  • 实例083 实现跨数据库的表内容复制 实例084 使用UNION ALL语句批量插入数据 实例085 更新指定记录 实例086 将数据表清空 第4章 SQL语句应用技术 4.1 聚集函数与日期查询 实例087 利用SUM函数实现数据汇总 实例088 ...
  • 内容简介 本系列图书包括第I卷、第II卷共计1200个例子,本文档是第I卷,共计603个例子。本书以开发人员在项目开发中经常遇到的问题和必须掌握的技术为中心,介绍了应用Java进行桌面程序开发各个方面的知识和技巧,...
  • 内容简介 本系列图书包括第I卷、第II卷共计1200个例子,本文档是第I卷,共计603个例子。本书以开发人员在项目开发中经常遇到的问题和必须掌握的技术为中心,介绍了应用Java进行桌面程序开发各个方面的知识和技巧,...
  • 内容简介 本系列图书包括第I卷、第II卷共计1200个例子,本文档是第I卷,共计603个例子。本书以开发人员在项目开发中经常遇到的问题和必须掌握的技术为中心,介绍了应用Java进行桌面程序开发各个方面的知识和技巧,...
  • 内容简介 本系列图书包括第I卷、第II卷共计1200个例子,本文档是第I卷,共计603个例子。本书以开发人员在项目开发中经常遇到的问题和必须掌握的技术为中心,介绍了应用Java进行桌面程序开发各个方面的知识和技巧,...
  • 内容简介 本系列图书包括第I卷、第II卷共计1200个例子,本文档是第I卷,共计603个例子。本书以开发人员在项目开发中经常遇到的问题和必须掌握的技术为中心,介绍了应用Java进行桌面程序开发各个方面的知识和技巧,...
  • Java开发实战1200例.第2卷.part3

    热门讨论 2013-05-08 22:46:34
    实例083 实现跨数据库的表内容复制 156 实例084 使用UNION ALL语句批量插入数据 156 实例085 更新指定记录 157 实例086 将数据表清空 159 第4章 SQL语句应用技术 160 4.1 聚集函数与日期查询 161 实例087 利用SUM...
  • Java开发实战1200例.第2卷.part2

    热门讨论 2013-05-08 22:45:35
    实例083 实现跨数据库的表内容复制 156 实例084 使用UNION ALL语句批量插入数据 156 实例085 更新指定记录 157 实例086 将数据表清空 159 第4章 SQL语句应用技术 160 4.1 聚集函数与日期查询 161 实例087 利用SUM...
  • Java开发实战1200例.第2卷.part1

    热门讨论 2013-05-08 22:44:13
    实例083 实现跨数据库的表内容复制 156 实例084 使用UNION ALL语句批量插入数据 156 实例085 更新指定记录 157 实例086 将数据表清空 159 第4章 SQL语句应用技术 160 4.1 聚集函数与日期查询 161 实例087 利用SUM...
  • 5. T_bulletin(公告及动态信息) 19 6. T_project_fund(项目资金信息) 19 7. T_project_info(项目基本信息) 19 8. T_project_fund_type(项目资金类型) 19 9. T_project_fund_source(项目资金来源...
  • 实例112 动态交叉(SQL Server 2000) 202 实例113 利用Pivot实现交叉查询 (SQL Server 2005) 204 实例114 用Unpivot实现交叉查询 (SQL Server 2005) 205 3.19 透视图表查询 207 实例115 动态透视...
  • 实例112 动态交叉(SQL Server 2000) 202 实例113 利用Pivot实现交叉查询 (SQL Server 2005) 204 实例114 用Unpivot实现交叉查询 (SQL Server 2005) 205 3.19 透视图表查询 207 实例115 动态透视...
  • 九九乘法 44 实例036 用while循环计算1+1/2!+1/3!…1/20! 45 实例037 for循环输出空心的菱形 46 实例038 foreach循环优于for循环 47 实例039 终止循环体 48 实例040 循环体的过滤器 49 实例041 循环的极限 50 第3...

空空如也

空空如也

1 2 3 4 5 ... 10
收藏数 192
精华内容 76
关键字:

员工动态表内容