模糊查询

LIKE 操作符用于在 WHERE 子句中搜索列中的指定模式。

可以和通配符(%、_)配合使用,其中"%"表示0或多个任意的字符,"_"表示一个任意的字符

语法:SELECT 列 | * FROM 表名 WHERE 列名 LIKE 值

示例:

-- 25.查询emp表中姓名中以"刘"字开头的员工,显示员工姓名。

-- 姓名中的第一个字必须是'刘',后面的都无所谓

select name from emp where name like '刘%';

-- 26.查询emp表中姓名中包含"涛"字的员工,显示员工姓名。

-- '%涛%'包含: 以'涛'开头,以'涛'结尾,或者'涛'在中间的某一个位置

select name from emp where name like '%涛%';

-- 27.查询emp表中姓名以"刘"开头,并且姓名为两个字的员工,显示员工姓名。

-- '刘_'表示以'刘'开头,并且姓名长度为2

```select name from emp where name like '刘_';`

-- '刘__'表示以'刘'开头,并且姓名长度为3

select name from emp where name like '刘__';

多行函数查询

多行函数也叫做聚合(聚集)函数,根据某一列或所有列进行统计。

常见的多行函数有:

多行函数

作用

COUNT( 列名 | * )

统计结果集中指定列的记录的行数。

MAX( 列名 )

统计结果集中某一列值中的最大值

MIN( 列名 )

统计结果集中某一列值中的最小值

SUM( 列名 )

统计结果集中某一列所有值的和

AVG( 列名 )

统计结果集中某一列值的平均值

提示:
(1)多行函数不能用在where子句中

(2)多行函数和是否分组有关,分组与否会直接影响多行函数的执行结果。

(3)多行函数在统计时会对null值进行过滤,直接将null值丢弃,不参与统计。

-- 28.统计emp表中薪资大于3000的员工个数

-- 查询薪资大于3000的员工有哪些

select * from emp where sal>3000;

-- 统计上面的查询结果有多少行记录(也就是薪资大于3000的员工个数)

select count(*) from emp where sal>3000; -- 7
select count(id) from emp where sal>3000; -- 7
select count(bonus) from emp where sal>3000; -- 6(有误差,因为null值不参与统计)

-- 29.求emp表中的最高薪资

-- 求员工表中的所有薪资

select sal from emp;

-- max(sal): 求sal这一列中的最大值

select max(sal) from emp;
select min(sal) from emp;

-- 30.统计emp表中所有员工的薪资总和(不包含奖金)

-- sum(sal): 求sal这一列中所有值的总和

select sum(sal) from emp;

-- sum(bonus): 即使bonus中有null值,sum函数会剔除null,不让null参与统计

select sum(bonus) from emp;

-- 31.统计emp表员工的平均薪资(不包含奖金)

-- avg(sal): 求sal这一列中所有薪资的平均值

select avg(sal) from emp;

多行函数需要注意的问题:

  • 多行函数和是否分组有关,如果查询结果中的数据没有经过分组,默认整个查询结果是一个组,多行函数就会默认统计当前这一个组的数据。产生的结果只有一个。
  • 如果查询结果中的数据经过分组(分的组不止一个),多行函数会根据分的组进行统计,有多少个组,就会统计出多少个结果。
select * from emp;

例如:统计emp表中的人数

-- 没有分组,默认所有员工是一个组,统计emp中的所有人数

select count(*) from emp; -- 12

结果返回的就是emp表中的所有人数

再例如:根据性别对emp表中的所有员工进行分组,再统计每组的人数,显示性别和对应人数

-- 按照性别分组,分为两个组,根据两个组统计,得出两个结果

select gender,count(*) from emp group by gender;

分组查询

GROUP BY 语句根据一个或多个列对结果集进行分组。

在分组的列上我们可以使用 COUNT,SUM,AVG,MAX,MIN等函数。

语法:SELECT 列 | * FROM 表名 [WHERE子句] GROUP BY 列;

-- 32.对emp表,按照部门对员工进行分组,查看分组后效果。

-- 根据部门对员工分组, 部门这一列值相同的为一组(共3组)

select * from emp group by dept;

-- 对分组后的员工进行统计,统计每一组的人数

select dept,count(*) from emp group by dept;

-- 33.对emp表按照职位进行分组,并统计每个职位的人数,显示职位和对应人数

-- 根据职位对员工分组, 职位这一列值相同的为一组(共3组)

select * from emp group by job;

-- 对上面分组后的员工进行统计,统计每一组的人数

select job,count(*) from emp group by job;

-- 34.对emp表按照部门进行分组,求每个部门的最高薪资(不包含奖金),显示部门名称和最高薪资

-- 根据部门分组,部门这一列相同的为一组(共3组)

select * from emp group by dept;

-- 对上面分组后的员工进行统计,统计每一组中的最高薪资

select dept,max(sal) from emp group by dept;

排序查询

使用 ORDER BY 子句将结果集中记录根据指定的列排序后再返回

语法:SELECT 列名 FROM 表名 ORDER BY 列名 [ASC|DESC]

ASC(默认)升,即从低到高;DESC 降序,即从高到低。

-- 35.对emp表中所有员工的薪资进行升序(从低到高)排序,显示员工姓名、薪资。

-- 按照薪资sal升序排序(默认就是asc,即升序)

select name,sal from emp order by sal;
select name,sal from emp order by sal asc;

-- 36.对emp表中所有员工的奖金进行降序(从高到低)排序,显示员工姓名、奖金。

-- 按照奖金bonus降序排序(desc是降序,不能省略)

select name,bonus from emp order by bonus desc;

-- 按照奖金bonus降序排序,对于奖金相同记录,再按照薪资进行升序排序

select name,bonus,sal from emp order by bonus desc,sal asc;

-- 39.查询emp表中所有【在1993和1995年之间出生】的员工,显示姓名、出生日期。

select name, birthday from emp
where birthday >= 1993 and birthday <= 1995;
-- 年月日不能和年份比较,错误!
-- 正确写法1: 将年月日中的年份提取出来,和年份进行比较
select name, birthday from emp
where year(birthday) >= 1993 and year(birthday) <= 1995;
-- 正确写法2: 将右面的年份转成年月日格式,和birthday进行比较
select name, birthday from emp
where birthday >= '1993-1-1' and birthday <= '1995-12-31';

-- 40.查询emp表中本月过生日的所有员工

-- 查询本月过生日的员工
select * from emp where month( now() )=month( birthday );
-- 查询下个月过生日的员工(考虑特殊月份,12月、11月)
select * from emp
where ( month(now())+1 )%12=month(birthday)%12;

-- 41.查询emp表中员工的姓名和薪资(薪资格式为: xxx(元) )

select name, concat(sal,'(元)') from emp;
-- 添加别名
select name 姓名, concat(sal,'(元)') 薪资 from emp;

-- 补充练习:查询emp表中员工的姓名和薪资(薪资格式为: xxx/元 )

select name, concat(sal,'/元') from emp;
select name, concat_ws('/',sal,'元') from emp;

mysql的数据类型

数值类型

MySQL中支持多种整型,其实很大程度上是相同的,只是存储值的大小范围不同而已。

**tinyint**:占用1个字节,相对于java中的byte

**smallint**:占用2个字节,相对于java中的short

**int**:占用4个字节,相对于java中的int

**bigint**:占用8个字节,相对于java中的long

其次是浮点类型即:float和double类型


**float**:4字节单精度浮点类型,相对于java中的float

**double**:8字节双精度浮点类型,相对于java中的double

字符串类型

1、char(n) 定长字符串,最长255个字符。n表示字符数,例如:

-- 创建user表,指定用户名为char类型,字符长度不超过10

create table user(
username char(10),
...
);

所谓的定长,是当插入的数据的长度小于指定的长度时,剩余的空间会用空格填充。(这样会浪费空间)

char类型往往用于存储长度固定的数据。

2、varchar(n) 变长字符串,最长不超过65535个字节,n表示字符数,一般超过255个字符,会使用text类型,例如:

iso8859-1码表:一个字符占用1个字节,1*n < 65535, n最多等于 65535
utf8码表:一个中文汉字占用3个字节,3*n < 65535,n最多等于 65535/3
GBK码表:一个中文汉字占用2个字节,2*n < 65535,n最多等于 65535/2

-- 创建user表,指定用户名为varchar类型,长度不超过10个字符

create table user(
username varchar(10)
);

所谓的不定长,是当插入的数据的长度小于指定的长度时,剩余的空间可以留给别的数据使用。(节省空间)

总结:长度固定的数据,用char类型,这样既不会浪费空间,效率也比较高

如果长度不固定,使用varchar类型,这样不会浪费空间。

3、大文本(长文本)类型

最长65535个字节,一般超过255个字符列的会使用text。

-- 创建user表:

create table user(
resume text
);

另,text也分多种,其中bigtext存储数据的长度约为4GB。

扩展内容3:(面试题)char(n)、varchar(n)、text都可以表示字符串类型,其区别在于:

(1)char(n)在保存数据时,如果存入的字符串长度小于指定的长度n,后面会用空格补全,因此可能会造成空间浪费,但是char类型的存储速度较varchar和text快。

因此char类型适合存储长度固定的数据,这样就不会有空间浪费,存储效率比后两者还快!

(2)varchar(n)保存数据时,按数据的真实长度存储,剩余的空间可以留给别的数据用,因此varchar不会浪费空间。

因此varchar适合存储长度不固定的数据,这样不会有空间的浪费。

(3)text是大文本类型,一般文本长度超过255个字符,就会使用text类型存储。

日期类型


**date**:年月日

**time**:时分秒

**datetime**:年月日 时分秒

timestamp:时间戳(实际存储的是一个时间毫秒值),与datetime存储日期格式相同。两者的区别是:

  • timestamp最大表示2038年,而datetime范围是1000~9999
  • timestamp在插入数据、修改数据时,可以自动更新成系统当前时间(后面用到时再做讲解)

连接查询

-- 42.查询部门和部门对应的员工信息

select * from dept,emp;

上面的查询中存在大量错误的数据,一般我们不会直接使用这种查询。

笛卡尔积查询:所谓笛卡尔积查询就是指,查询两张表,其中一张表有m条记录,另一张表有n条记录,查询的结果是m*n条。

虽然笛卡尔积查询中包含大量错误数据,但我们可以通过where子句将错误数据剔除,保留下来的就是正确数据。

-- 通过where子句将笛卡尔积查询结果中错误的数据剔除,保留正确数据!
select * from dept,emp
where emp.dept_id=dept.id;
-- 因为id在两张表中都存在,所以为了区分,必须在列名前面加上[表名.]

通过where子句将笛卡尔积查询中的错误数据剔除,保留正确的数据,这就是连接查询!

上面的查询可以换成下面的查询:

select * from dept inner join emp
on emp.dept_id=dept.id;
-- 内连接查询,结果和上面的连接查询相同!

左外连接查询

-- 43.查询【所有部门】及部门对应的员工,如果某个部门下没有员工,员工显示为null

-- 查询的结果中都是有员工的部门和有部门的员工
select * from dept, emp
where emp.dept_id=dept.id;
-- 如果要查询部门表中的所有部门,以及部门对应的员工
select * from dept left join emp
on emp.dept_id=dept.id;

连接查询

-- 42.查询部门和部门对应的员工信息

select * from dept,emp;

上面的查询中存在大量错误的数据,一般我们不会直接使用这种查询。

笛卡尔积查询:所谓笛卡尔积查询就是指,查询两张表,其中一张表有m条记录,另一张表有n条记录,查询的结果是m*n条。

虽然笛卡尔积查询中包含大量错误数据,但我们可以通过where子句将错误数据剔除,保留下来的就是正确数据。

-- 通过where子句将笛卡尔积查询结果中错误的数据剔除,保留正确数据!

select * from dept,emp where emp.dept_id=dept.id;

-- 因为id在两张表中都存在,所以为了区分,必须在列名前面加上[表名.]

通过where子句将笛卡尔积查询中的错误数据剔除,保留正确的数据,这就是连接查询!

上面的查询可以换成下面的查询:

select * from dept inner join emp on emp.dept_id=dept.id;

-- 内连接查询,结果和上面的连接查询相同!

左外连接查询

-- 43.查询【所有部门】及部门对应的员工,如果某个部门下没有员工,员工显示为null

-- 查询的结果中都是有员工的部门和有部门的员工

select * from dept, emp where emp.dept_id=dept.id;

-- 如果要查询部门表中的所有部门,以及部门对应的员工

select * from dept left join emp on emp.dept_id=dept.id;

左外连接查询:可以将左边表中的所有记录都查询出来,右边表只显示和左边相对应的数据,如果左边表中某些记录在右边没有对应的数据,右边显示为null即可。

右外连接查询

-- 44.查询【所有员工】及员工所属的部门,如果某个员工没有所属部门,部门显示为null即可

-- 查询的结果中都是有员工的部门和有部门的员工
select * from dept, emp
where emp.dept_id=dept.id;
-- 如果要查询所有员工及员工对应的部门
select * from dept right join emp
on emp.dept_id=dept.id;

右外连接查询

-- 44.查询【所有员工】及员工所属的部门,如果某个员工没有所属部门,部门显示为null即可

-- 查询的结果中都是有员工的部门和有部门的员工

select * from dept, emp where emp.dept_id=dept.id;

-- 如果要查询所有员工及员工对应的部门

select * from dept right join emp on emp.dept_id=dept.id;

全外键查询

扩展:如果想将两张表中的所有数据都查询出来(左外+右外并去除重复记录),可以使用全外连接查询,但是mysql又不支持全外连接查询。


select * from dept left join emp on emp.dept_id=dept.id
union
select * from dept right join emp on emp.dept_id=dept.id;

可以使用union将左外连接查询的结果和右外连接查询的结果合并在一起,并去除重复的记录。例如:

需要注意的是:union可以将两条SQL语句执行的结果合并,但是有前提:

(1)两条SQL语句查询的结果列数必须一致

(2)两条SQL语句查询的结果列名、顺序也必须一致

并且union默认就会将两个查询中重复的记录去除(如果不希望去除重复记录,可以使用union all)

子查询练习

-- 准备数据:以下练习将使用db40库中的表及表记录,请先进入db40数据库!!!

-- 45.列出薪资比'王海涛'的薪资高的所有员工,显示姓名、薪资

-- 求出'王海涛'的薪资

select sal,name from emp where name='王海涛'; -- 2450

-- 求比'王海涛'薪资还高的员工

select name,sal from emp where sal>(select sal from emp where name='王海涛');

-- 子查询: 将一条SQL语句执行的结果作为另外一条SQL语句的条件来执行,这种查询叫做子查询

-- 46.列出与'刘沛霞'从事相同职位的所有员工,显示姓名、职位。

-- 求出'刘沛霞'从事的职位

select job from emp where name='刘沛霞'; -- 推销员

-- 求出和'刘沛霞'从事相同职位的员工

select name,job from emp where job=(select job from emp where name='刘沛霞');

列出薪资比'大数据部'部门(已知部门编号为30)所有员工薪资都高的员工信息,显示员工姓名、薪资和部门名称。

如果不考虑没有部门的员工

-- 连接查询员工表和部门表

select emp.name,sal,dept.name from emp,dept
where emp.dept_id=dept.id;

-- 求出大数据部门的最高薪资

select max(sal) from emp where dept_id=30; -- 3000

-- 求薪资比大数据部门最高薪资还高的员工

select emp.name,sal,dept.name from emp,dept
where emp.dept_id=dept.id
 and sal>(select max(sal) from emp where dept_id=30);
03-05 23:36