前言
花了一点时间整理了SQL的一些查询操作,包括分组查询、排序查询、case函数、自连接、内连接、外连接等,结合Mybatis完成了一个个的案例。
一、建立数据库
该数据库包含五张表,每张表都有多个字段,博主已经上传了数据库的相关资源。在正式开始前,博主需要交代几点。在mybatis中,无论你指定还是不指定返回类型,mybatis都会默认地先将查询完成后返回的值放入一个HashMap中(如果返回的值不止一条,就会放入一个包含HashMap的list集合中)。指定与不指定的区别在于,如果你指定了返回类型,mybatis将会根据返回类型的实体类来从HashMap中获取值并set到这个实体类中。如果不指定就默认返回HashMap<Object,Object>(List<HashMap<Object,Object>>)。在查询时,你是否遇到查询表中的某些字段,会显示该表的所有信息?如何输出特定字段呢?大概有三种方法:
1、创建一些自己要用到的实体类,类中写自己要输出的字段,对应好即可
2、如果嫌写实体类麻烦,也可以不写,不写实体类系统就会自动创建HashMap来为你封装数据,我们就直接拿到这个map就可以了,可以用List<Map<Object,Object>>这种通用对象来接收Mybatis的查询结果。这种方法可以偷懒,我就是用这种方法偷的懒,但在博主实践的过程中,字段为null的时候好像不会输出,所以不是很推荐。这种不用写实体类的SQL操作,适用于字段和表名都是程序运行时产生的,实际上很多灵活性和扩展性要求比较高的应用,表的结构不能够确定,甚至连表名字都不确定,所以SQL语句和实体类映射字段不能被写死。
3、Mybatis plus提供了条件构造器,其中的queryWrapper可以实现查找指定字段。
二、案例实战
注:因为mysql不区分字段大小写,所以字段名往往会带下划线,如果要将数据库字段名与实体类对应上就需要在mybatis配置文件中开启驼峰命名
<settings>
<setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>
1、查询工资在10000到20000之间的员工名、工资以及奖金,并按工资从高到低排序
List<Map<Object, Object>> querySalary();
<select id="querySalary" resultType="map">
select first_name, salary, commission_pct
from myemployees.employees
where salary between 10000 and 20000
order by salary desc
</select>
结果: 从结果就可以看出来用List<Map<Object,Object>>的弊端了,没有奖金的员工不显示出他的奖金率。
2、 查询员工号为176的员工的姓名和部门号和年薪
Map<Object, Object> queryByID(@Param("id") int employee_id);
<select id="queryByID" resultType="map">
SELECT CONCAT(first_name,last_name) 姓名,
department_id 部门号,
salary * 12 * (1 + IFNULL(commission_pct, 0)) 年薪
FROM myemployees.employees
WHERE employee_id = #{id};
</select>
结果:
3、查询没有奖金,且工资小于18000员工的salary,first_name,并按工资从高到低排序
注:Mybatis中使用小于号需要用转义字符,"<","<"
<select id="queryNoPct" resultType="map">
select first_name 名字,salary 薪水
from myemployees.employees
where commission_pct is null and salary <18000 order by salary desc
</select>
结果:
4、案例如下:
/*现公司出台一个政策,即要给员工的工资进行一个评级,评级状况如下: * 工资大于20000的,评级为A级别 * 工资大于15000的,评级为B级别 * 工资大于10000的,评级为C级别 * 工资小于10000的,均评级为D级别 * 要求:输出员工的姓名,工资和工资评级状况,按工资高到低输出 * */
<select id="queryByRank" resultType="map">
select CONCAT(first_name,' ',last_name) 姓名,salary 工资,
CASE
when salary>20000 then 'A级别'
when salary>15000 then 'B级别'
when salary>10000 then 'C级别'
else 'D级别' end as 工资级别
from myemployees.employees
order by salary desc
</select>
结果: 107条记录还是挺多的哈,截不全请见谅!
5、案例如下:
/*查询每个工种有奖金的员工的最高工资>12000的工种编号和最高工资 * 思路:该需求用到分组查询 * 1、先查询每个工种有奖金的员工的最高工资 * 2、根据1的结果继续筛选,选择最高工资>12000; * */
<select id="queryByGroup" resultType="map">
select job_id 工种编号,max(salary) 最高工资
from myemployees.employees
where commission_pct is not null
GROUP BY job_id
having 最高工资 > 12000
</select>
结果:
6、案例如下:
/*查询员工姓名、部门名和所在城市,城市名以s开头 * 思路:员工名出现在员工表employees中,部门名出现在departments表中,而城市名出现在 locations表中 * 此案例涉及到了三表查询,根据employees表的外键department_id连接到departments表,然后根据departments表的 * 外键location_id连接到locations表 * */
<select id="queryMoreTables" resultType="map">
select concat(first_name,' ',last_name) 姓名,department_name 部门名,city 城市名
from myemployees.employees e,myemployees.departments d,myemployees.locations l
where e.department_id=d.department_id and d.location_id=l.location_id and
city like 's%'
order by department_name desc
</select>
结果:
7、案例如下:
/*案例:查询所有的部门里面员工个数大于3的部门名以及具体的员工数量,查询结果按员工数量降序排序, * 这里用内连接(自然连接或普通连接)去实现,内连接:就是两张表只显示符合连接条件的行(可以理解为取两张表的交集) * 所以内连接可能会丢失信息 * */
<select id="queryInner" resultType="map">
SELECT department_name,COUNT(*)
FROM myemployees.departments d
inner join myemployees.employees e
on d.department_id=e.department_id
GROUP BY department_name
HAVING COUNT(*)>3
ORDER BY COUNT(*) desc;
</select>
结果:
8、 案例如下:
/*查询姓名中包含字符K的员工的名字及其上级的名字 因为员工表中既包含打工仔和打工仔的boss,所以,可以通过员工的manager_id找到employee_id,进 而找到boss的name * 当表中的某一个字段和这张表中另外字段相关时,可以用自连接,所以此查询使用自连接 * */
<select id="querySelfJoin" resultType="map">
SELECT e.first_name 员工名,m.first_name 老板名
from myemployees.employees e
join myemployees.employees m
on m.employee_id=e.manager_id
WHERE e.first_name like '%k%';
</select>
结果:
9、 案例如下:
/*查询哪个部门没有员工 * 这里只需将部门的信息全部输出并且employee_id=null即可,所以这里用的是左外连接 * 左外连接(右边的表不加限制),以左表为基准,查询出左表所有的数据和右表中连接字段相等的记录, 如果右表中没有对应数据,则显示为空(NULL) * 右外连接(右边的表不加限制),以右表为基准,查询出右表所有的数据和左表中连接字段相等的记录, 如果左表中没有对应数据,则显示为空(NULL) * 全外连接(左右两表都不加限制),左右两表的所有字段名均列出(且各只出现一次) 不符合on表达式的字段为null * */
<select id="queryNoEmployees1" resultType="map">
SELECT d.*,e.employee_id
FROM myemployees.departments d
LEFT JOIN myemployees.employees e
on d.department_id=e.department_id
WHERE e.employee_id is NULL;
</select>
<select id="queryNoEmployees2" resultType="map">
SELECT d.*,e.employee_id
FROM myemployees.employees e
right JOIN myemployees.departments d
on d.department_id=e.department_id
WHERE e.employee_id is NULL;
</select>
结果:
10、 案例如下:用的是实体类查询指定字段,自己也可以给出自己喜欢的输出格式,但不是很方便。
/*指定返回类型为实体类,Sql查询到的内容就映射到相关实体类的属性中, * 需要用多对一来实现三表查询 * 案例:查询员工姓名、部门名和所在城市,城市名以s开头 * 分析:多个员工可能位于同一个部门,可能位于同一城市 * 也就是说多个员工关联一个部门,一个城市 */
Employees.java
package com.pojo;
public class Employees {
private String firstName;
private String lastName;
private Departments departments;
private Locations locations;
public Employees() {
}
public Employees(String firstName, String lastName, Departments departments, Locations locations) {
this.firstName = firstName;
this.lastName = lastName;
this.departments = departments;
this.locations = locations;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public Departments getDepartments() {
return departments;
}
public void setDepartments(Departments departments) {
this.departments = departments;
}
public Locations getLocations() {
return locations;
}
public void setLocations(Locations locations) {
this.locations = locations;
}
@Override
public String toString() {
return "姓名:" + firstName + " " + lastName +" "+ departments+" "+locations;
}
}
Departments.java
package com.pojo;
public class Departments {
private String departmentName;
public Departments(){
}
public Departments( String departmentName) {
this.departmentName = departmentName;
}
public String getDepartmentName() {
return departmentName;
}
public void setDepartmentName(String departmentName) {
this.departmentName = departmentName;
}
@Override
public String toString() {
return " 部门名:" + departmentName ;
}
}
Locations.java
package com.pojo;
public class Locations {
private String city;
public Locations(){
}
public Locations(String city) {
this.city = city;
}
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
@Override
public String toString() {
return "城市名:" + city ;
}
}
<select id="queryByGroup2" resultMap="toDepartments">
select last_name 姓,first_name 名字,department_name 部门名,city 城市名
from myemployees.employees e,myemployees.departments d,myemployees.locations l
where e.department_id=d.department_id and d.location_id=l.location_id
and city like 's%'
order by department_name desc
</select>
<resultMap id="toDepartments" type="Employees" >
<result property="lastName" column="姓"/>
<result property="firstName" column="名字"/>
<association property="departments" javaType="Departments">
<result property="departmentName" column="部门名"/>
</association>
<association property="locations" javaType="Locations">
<result property="city" column="城市名"/>
</association>
</resultMap>
结果: