MySql基础查询语句复习(补充增删改语句)

前言  

本人写下这篇博客是帮助自己加深对SQL语句的理解,以及复习所学知识,加深印象,记录学习过程,起初是只想复习查询语句,但是后面想着写都写了,就继续加了增删改的基础语句复习

目录

前言  

数据表的建立

数据插入

数据查询

数据查询之where条件查询

简单的查询

精确条件查询

补充:数据修改

补充:数据插入

补充:数据删除

模糊条件查询

范围查询、离散查询、清楚重复值

统计查询(聚合函数)

concat连接

数据查询之分组查询(group by)

数据查询之having条件筛选查询

数据查询之order by排序查询

数据查询之limit限制查询

数据查询之exits型子查询

数据查询之左连接查询和右连接查询、

数据查询之内连接查询

数据查询之联合查询

union查询的注意事项

union all查询

总练习


数据表的建立

在学习之前,我们需要几张数据表来实现查询操作,就拿最平常的员工表来进行示范

创建员工表

create table employee(
enumber INT primary key comment'员工编号',
ename VARCHAR(10) comment'员工姓名',
dname VARCHAR(20) comment'所属部门',
job VARCHAR(20) comment'员工职位',
salary INT comment'员工工资',
dnumber INT comment'部门编号'
);

创建部门表

CREATE TABLE department (
dnumber INT COMMENT '部门编号',
dname VARCHAR(20) COMMENT '部门名称',
addr VARCHAR(20) COMMENT '部门地址'  
);

数据插入

创建完表后,往里面插入数据

INSERT INTO department values ('01','研发部','上海');
INSERT INTO department values ('02','销售部','北京');
INSERT INTO department values ('03','财务部','深圳');

INSERT INTO employee values ('1101','赵一','研发部','后端','11000','01');
INSERT INTO employee VALUES (1102, '王二', '研发部', '后端', 12000, 01);
INSERT INTO employee VALUES (1103, '张三', '研发部', '前端', 13000, 01);
INSERT INTO employee VALUES (1104, '李四', '销售部', '前端', 9000, 02);
INSERT INTO employee VALUES (1105, '张三', '研发部', '运维', 10000, 01);
INSERT INTO employee VALUES (1106, '刘五', '财务部', '会计', 9500, 03);
INSERT INTO employee VALUES (1107, '陈六', '研发部', '测试', 10000, 01);
INSERT INTO employee VALUES (1108, '胡七', '财务部', '会计', 9000, 03);
INSERT INTO employee VALUES (1109, '何八', '销售部', '销售员', 9200, 02);

好了,两张表已经建立好了,接下来看下两张表的内容

创建成功!

数据查询

数据查询之where条件查询

简单的查询

select * from employee;   
--*代表全部,意思是查询employee表中的全部信息


select enumber,ename,job as ename_job from employee; 
--as意为给job起个别名,叫ename_job

as会为表起个别名,还有一点要提的是,执行查询语句后并不会创建新的表,查询语句的本质是从现有表中查询数据,结果以临时结果集的形式返回(内存或临时表中),但不会持久化存储为新表。

或者这样使用

 select enumber,ename as 名字,job as ename_job from employee;

精确条件查询

select * from employee where ename='张三';
select * from employee where salary != 10000;
select * from employee where salary <> 10000;
select * from employee where salary > 10000;

可以用where匹配条件,切记!语句中的匹配条件要与字符类型对应,ename的字符串类型为VARCHAR,salary的类型为INT。

!=:不等于;  <>:不等于;  >:大于;  <:小于;用于INT类型的时候

其实根据英文一眼就能看出来所代表的意思

补充:数据修改

好吧,由于作者的疏忽,这里查询张三的时候,出现了两行。。。

我们修改下数据吧

update employee set ename='飞飞' where enumber=1105;

 这样编号为1105的那一行数据中,ename从张三改为了飞飞

关于修改语句,这里也一并补充一下

UPDATE 表名 SET 列1 = 值1, 列2 = 值2, ...
WHERE 条件;  -- 筛选需要修改的记录,若省略则修改全量数据

比如我要修改飞飞的工资,工作之类的

update employee set salary=50000 where enumber=1105;

update employee set job='后端' where ename='飞飞';

如果没有where条件,sql语句将会把所有人的工资和工作修改(后端要崛起了)

当然,也可以多行修改

update employee set department = '销售部', job = '销售经理' where ename = '飞飞';

将飞飞的部门和职位都改变 

 批量修改

update employee set salary = 10000 where salary < 10000;

 将工资少于10000的人的工资改为10000(涨薪!)

补充:数据插入

语法很简单

insert into 表名(字段名) values(字段对应值);
insert into employee values (1110, '宇宇', '销售部', '销售大师', 11500, 2);

还有一些其他的玩法,比如只插入一些

insert into employee (enumber,job) values (1111,'后端');

那么显示出来的数据

切记,一定这些列的约束条件默认为空,也就是default null,在创建表的时候,不写约束条件就是默认为空,如果是not null,就会报错。一般插入条件是,只要将每一列的数据都填入进去,是可以省略字段名的,因为系统会一一对应,如果对应不上的话,就会报错 ,比如

只有一个values值1112导致无法对应,还有,字段名一定要加上括号。INT类型不要用'单引号'

插入还有一些其他的玩法

将表名2的数据复制到表名1中

insert into 表名1 select * from 表名2;

insert into 表名1(字段名1,字段名2) select 字段名1,字段名2 from 表名2;

insert into worker (enumber,ename) select enumber,ename from employee;

建表复制

create table 表名1 as select 字段名1,字段名2 from 表名2;

create table worker as select enumber ,ename from employee;

如果要复制整张表,就直接改为*(星号)

还有一次性插入多个数据

insert into 表名 (字段名) values (对应值1),(对应值2),(对应值3);

insert into worker values (1112,'一一'),(1113,'二二');

 

补充:数据删除

DELETE FROM 表名 WHERE 条件;

-- 示例:删除 worker 表中编号为 1102 的员工
DELETE FROM worker WHERE enumber = 02;

-- 注意:不带 WHERE 条件会删除全量数据!
DELETE FROM worker;  -- 清空表,但保留表结构

删除整张表

truncate table 表名;(也可以不写table)

delete from 表名;

drop table 表名;

这三个之间是有差别的

delete 会把删除的操作记录给记录起来,可以数据回退,不会释放空间,而且不会删除定义。

truncate不会记录删除操作,会把表占用的空间恢复到最初,不会删除定义

drop会删除整张表,释放表占用的空间。 不可恢复!

 进行delete和truncate操作后,仍然可以往表里插入数据,但是使用drop后,无法再往表里插入数据,因为这张表不存在了,要重新建表,我们可以把worker表删了。

使用truncate

使用drop

 可以明显看到,使用drop后,无法再往worker中插入数据,因为这张表已经不存在了

模糊条件查询

查询当前列表中姓王的人

select * from employee where ename like '王%';

这样的效果也是一样的,会显示王二; 

select * from employee where enumber like '11%2';

范围查询、离散查询、清楚重复值

范围查询主要用到between···and···(跟英语一样)

select * from employee where salary between 10000 and 20000;

查询工资10000到20000的人

离散查询

select * from employee where ename in ('张三','李四','小红','小胡');

select * from employee where enumber in (1103,1104);

在括号里面查询这些人,会查询到已有的人,两次查询结果是一样的

清楚重复值

select distinct(job) from employee;

select job from employee;

清楚job的重复值,两次输出结果不一样

可以看到,上面清楚重复值后只有7行,而下面有14行

统计查询(聚合函数)

聚合查询是指使用聚合函数,像计算avg()、sum()、min()、sum()等等这些对数据进行分组统计的查询。聚合函数一般与group by一起使用!

count

select count(*) from employee;
select count(ename) from employee;

可能有人会疑问为什么ename会是10,因为我们之前还创造了一列ename为空值的员工,具体看数据插入的补充部分

计算总值和平均值

在此之前先把第十一行删了吧

DELETE FROM employee WHERE enumber = 1111;

删完之后,我们来执行计算总值和平均值的sql语句

sum()   计算总和
select sum(salary) from employee;

avg()   计算平均值 
select avg(salary) from employee;

OK,非常完美,接下来是

查询数据的最大值与最小值

max() 查询最大值
select max(salary) as highest_salary from employee;
select * from employee where salary= (select max(salary) from employee);

min() 查询最低值
select min(salary) as lowest_salary from employee;
select * from employee where salary= (select min(salary) from employee);

第一种查询方式:

第二种查询

我们还是来讲解下第二种查询吧,第二种查询运用到了子查询,子查询仅返回单个值(一行或一列),这里子查询将(select min(salary) from employee)括号里的结果返回给where的过滤条件,如果单用子查询,只会有这个值,跟第一种一样,但是第一种用了as起了个别名。

concat连接

select concat(ename,' 是 ',job) as 员工 from employee;

concat会将两列连接起来那么如果不用as会怎样呢

这样一看很不美观,所以concat还是与as一起用

数据查询之分组查询(group by)

作用:把行 按 字段 分组

语法:group by 列1,列2....列N

适用场合:常用于统计场合,一般和聚合函数连用

select dnumber from employee group by dnumber;

select dnumber,count(*) from employee group by dnumber;

可以看到count(*)还将对应的数量显示出来的。还有group by的字句和select的字句必须一致!

select dnumber,job count(*) from employee group by dnumber,job;

如果不一致就会报错

数据查询之having条件筛选查询

作用:对查询的结果进行筛选操作

语法:having 条件 或者 having 聚合函数 条件

适用场合:一般跟在group by之后

having子句只能引用:

分组字段

聚合函数

不能直接引用未分组的列

select job,count(*) from employee group by job having job ='后端';

select dnumber,job,count(*) from employee group by dnumber,job having count(*)>=2;

select dnumber,job,count(*) as 总数 from employee group by dnumber,job having 总数>=2;

数据查询之order by排序查询

作用:对查询的结果进行排序操作

语法:order by 字段1,字段2 .....

适用场合:一般用在查询结果的排序

select * from employee order by salary;

当然,排序查询也支持布尔值、字符类型、时间类型的数据进行排序

排序查询也是支持升序降序的,升序asc,不写时默认为asc,降序desc

降序
select dnumber,job,count(*) as 总数 from employee group by dnumber,job having 总数>=2
order by dnumber desc;

升序
select dnumber,job,count(*) as 总数 from employee group by dnumber,job having 总数>=2
order by dnumber asc;

还有查询的顺序是:where ---- group by ----- having ------ order by

数据查询之limit限制查询

作用:对查询结果起到限制条数的作用

语法:limit n,m n:代表起始条数值,不写默认为0;m代表:取出的条数

适用场合:数据量过多时,可以起到限制作用

在之前的练习中,因为我们所创建的表比较小,所以可以用*,如果表的数据一旦多起来,用了*之后对性能的影响可想而知(好奇的可以去MySql自带表里select *一下,不过最好别)

select * from employee limit 5;
--limit(0,5)

select * from employee limit 5,5;

第一个语句是取employee表中的前五行 

第二个语句是从第四行开始,取五行,不包括第五行

数据查询之exits型子查询

exists型子查询后面是一个受限的select查询语句

exists子查询,如果exists后的内层查询能查出数据,则返回 TRUE 表示存在;为空则返回 FLASE则不存在。

分为exist和not exists两种类型

select * from department a 
where exists (select 1 from employee b where a.dnumber=b.dnumber);

select * from department a 
where not exists (select 1 from employee b where a.dnumber=b.dnumber);

先来看下两个语句的结果吧

第一个语句的意思是使用exist子查询来检索在employee表中至少有一名员工的部门记录。

在department和employee中,主查询为select * from department a ,以a为department表的别名

子查询则为括号里的,以b为employee表的别名,它的作用是查看是否存在部门编号(dnumber)与department表中当前记录相同的员工。

至于select 1 ,在 SQL 查询中,子查询里的select 1 是一种常用的写法,这里的1并没有特殊的含义,你也可以把它替换成*或者其他常量,比如2、'x'等。其核心作用是检查子查询是否能返回结果集,而不是关注返回的具体内容。

exists操作符只在乎子查询是否有返回行,一旦子查询能返回至少一行数据,exists就会返回true;要是子查询没有返回任何行,则返回false。

select 1比select *更高效,这只是子查询的一个简化

数据查询之左连接查询和右连接查询、

左连接称之为左外连接 右连接称之为右外连接 这俩个连接都是属于外连接

左连接关键字:left join 表名 on 条件 / left outer 表名 join on 条件

右连接关键字:right join 表名 on 条件/ right outer 表名 join on 条件

左连接说明: left join 是left outer join的简写,左(外)连接,左表(a_table)的记录将会全部表示出来, 而右表 (b_table)只会显示符合搜索条件的记录。右表记录不足的地方均为NULL。

右连接说明:right join是right outer join的简写,与左(外)连接相反,右(外)连接,左表(a_table)只会显示符合 搜索条件的记录,而右表(b_table)的记录将会全部表示出来。左表记录不足的地方均为NULL。

左连接查询

select a.addr,b.* from department a left join employee b on a.dnumber=b.dnumber;

以department为主表

右连接查询,以右表为主表

select a.*,b.ename from department a right join employee b on a.dnumber=b.dnumber;

数据查询之内连接查询

内连接查询的语法与左右连接查询相似

内连接:获取两个表中字段匹配关系的记录

主要语法:INNER JOIN 表名 ON 条件;

内连接只保留两边都匹配的记录

比如我们想查出飞飞所在部门的地址

select a.addr from department a inner join employee b 
on a.dnumber=b.dnumber and b.ename='飞飞';

也可以这样写,结果是一样的

select a.addr from department a,employee b 
where a.dnumber=b.dnumber and b.ename ='飞飞';

数据查询之联合查询

联合查询:就是把多个查询语句的查询结果结合在一起 主

要语法1:... UNION ... (去除重复)

主要语法2:... UNION ALL ...(不去重复)

union查询的注意事项

(1)两个select语句的查询结果的“字段数”必须一致;(类似于聚合查询)

select ename,dname,dnumber from employee 
union 
select dname,dnumber from department;
ERROR 1222 (21000): The used SELECT statements have a different number of columns

可以看到,如果不一致就会报错 

(2)通常,也应该让两个查询语句的字段类型具有一致性;

也就是VARCHAR 和INT这种,如果不一致的话,我们来举个例子,将上述的语句,第二个select语句以null来填充

select ename,dname,dnumber from employee 
union 
select dname,dnumber,null as dnumber from department;

 

可以看到,类型不一致的话会非常的不美观

(3)也可以联合更多的查询结果,也就是两个三个

(4)用到order by排序时,需要加上limit(加上最大条数就行),需要对子句用括号括起来,现在我们要对员工的工资进行排序

对后端员工工资升序排序,对前端员工工资降序排序,对会计工资升序

(select * from employee a where a.job = '后端' order by a.salary limit 999999 )
union 
(select * from employee b where b.job = '前端' order by b.salary desc limit 999999)
union
(select * from employee c where c.job = '会计' order by c.salary asc limit 999999);

这里有人可能会疑问为什么要加limit,这是因为,三个字句都被union联合起来了,MySQL 认为,union的结果是一个集合,理论上集合是无序的。因此,子查询中的order by通常会被优化器忽略,除非明确指定limit,如果不加limit,结果就会是

(select * from employee a where a.job = '后端' order by a.salary )
union 
(select * from employee b where b.job = '前端' order by b.salary desc )
union
(select * from employee c where c.job = '会计' order by c.salary asc );

可以看到,会计的工资不再是升序而变成降序,因为这里行数太少,不能更好的体现,但是记住,如果不用limit,union所联合的字句将不会是按照order by排序好的结果输出,而是无序!

union all查询

union all查询是不会去重的,我们可以简单的举几个例子

select ename, job, salary from employee where job = '后端'
union
select ename, job, salary from employee where ename = '赵一';

select ename, job, salary from employee where job = '后端'
union all
select ename, job, salary from employee where ename = '赵一';

可以看到是有差别的

在union中,第一个字句会显示工作是后端人员的列,第二个字句会显示名字叫赵一的列,但是union会自动去重,所以就展示了两列,而union all是不会自动去重的,所以会展示三列,也就是说union all会自动合并

在数据量大的时候使用union,对性能会有很大影响!

总练习

在复习完所有的知识后,来个总练习吧,补充一下,查询出来的信息表,主要由select和from中间的语句来决定

1.列出所有部门的部门编号,部门名称,部门地址,部门人数

select a.*,b.sum from 
department a,(select dnumber,count(*) as sum from employee group by dnumber) b 
where a.dnumber=b.dnumber;

部门表(department)为a表,至于b表则是括号里的子查询

select dnumber,count(*) as sum from employee group by dnumber

这里表示以部门编号为主,对部门里的人数进行排序,b表就是排序好的部门人数表

2.列出工资比飞飞高的员工

select ename from employee 
where salary > (select salary from employee where ename = '飞飞');

这个比较简单

3.列出部门名称和部门里员工的信息

select a.dname,b.ename,b.enumber,b.job from department a,employee b 
where a.dnumber=b.dnumber;

4.列出所有后端人员的姓名及其部门名称,所在部门总人数

这个可能有点复杂

select a.ename,b.dname,c.sum 
from employee a,department b,
(select dnumber,count(*) as sum from employee group by dnumber)c 
where a.job='后端' and a.dnumber=b.dnumber and a.dnumber=c.dnumber;

这是三个表的连接条件

a.dnumber=b.number关联员工表和部门表,确保员工所属部门正确。

a.dnumber=c.number关联员工表和子查询结果,获取员工所在部门的总人数。

5.列出最低薪金大于10000的各种工作及从事此工作的员工人数。

select job,count(*) from employee group by job having min(salary) > 10000;

这里还要记住group by的字句和select的字句必须一致!

还有这样一种情况

那么为什么会报错呢?这是因为在having子句中引用了 salary 列,但该列并未包含在group by或聚合函数中。MySQL 不允许直接在having中引用未分组的列。

6.列出与张三从事相同工作的所有员工及其部门名称

 两种都是一样的

select a.ename,b.dname from employee a,
department b where a.dnumber=b.dnumber 
and a.job=(select job from employee where ename='张三');
select a.ename,b.dname from employee a 
join department b on a.dnumber=b.dnumber 
where a.job=(select job from employee where ename='张三');

复习完毕!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值