CSDN话题挑战赛第2期
参赛话题:学习笔记
个人主页:BoBooY的CSDN博客_Java领域博主 前言:本篇文章总结了 MySQL的入门知识点(上),希望通过 文字介绍 代码 图片的形式帮助大家快速掌握 MySQL入门知识点(下):https://blog.csdn.net/qq_58233406/article/details/127144532 MySQL经典练习题 解题思路:https://blog.csdn.net/qq_58233406/article/details/127150051
文章目录
- MySQL(上篇)
- 一、了解数据库
- (一)数据库
- (二)数据库管理系统
- 常见的数据库管理系统
- (三)SQL
- 分类
- (四)三者的关系
- 二、MySQL常用命令
- (1)退出mysql
- (2)查看mysql中有哪些数据库
- (3)选择使用某个数据库
- (4)创建数据库
- (5)查看某个数据库下有哪些表
- (6)查看mysql数据库的版本号
- (7)查看当前使用的是哪个数据库
- (8)将sql文件中的数据导入
- (9)查看表结构
- (10)终止一条sql命令的执行
- (11)注意事项
- 三、DQL语句
- (一)简单查询
- 1.查询一个字段
- 2.查询多个字段
- 3.查询所有字段
- (1)方式一
- (2)方式二
- 4.给查询的列起别名
- (1)方式一:使用 as关键字 起别名。
- (2)方式二:省略as关键字 用空格代替
- (二)条件查询
- 1.格式
- 2.条件种类
- 3.排序数据
- 1.语法格式:
- 2.多个字段排序
- 3.根据字段位置排序(了解)
- 4.综合案例
- 5.数据处理函数(单行处理函数)
- 6.分组函数(多行处理函数)
- (1)种类(5个)
- (2)注意事项
- (三)分组查询(重要)
- (1)语法格式:
- (2)执行顺序
- (3)having条件
- (4)distinct
- 到这里单表查询结束
- (四)连接查询(非常重要)
- 1.概述
- 2.连接查询的分类
- 3.笛卡尔积现象
- 4.内连接
- (1)等值连接
- (2)非等值连接
- (3)自连接
- 5.外连接
- 6.内连接与外连接的区别
- 7.全连接(了解)
- 8.多张表连接
- (五)子查询
- 1.概述
- 2.where子句中的子查询
- 3.from中的子查询
- 4.select后面的子查询(了解)
- 5.union合并查询结果集
- 6.limit
- (六)DQL总结
- (一)简单查询
- 四、DDL语句
- (一)表的创建(建表)
- 1.语法格式
- 2.mysql中的数据类型
- 3.创建一个学生表
- 4.给字段设置默认值
- 5.快速创建表(了解)
- (二)表的删除
- 1.语法格式
- 2.注意事项
- (三)对表结构的增删改
- 修改表名
- 字段操作
- alter添加字段在指定位置
- alter删除字段
- alter修改字段类型及名称
- alter修改数据库字符集
- alter修改表字符集
- alter修改列字符集
- (四)约束(非常重要)
- 1.概述
- 2.约束的分类
- 3.非空约束:not null
- 4.唯一性约束: unique
- 5.主键约束: primary key
- 6.外键约束:foreign key
- (一)表的创建(建表)
- 五、DML语句
- (一)插入数据
- 1.语法格式
- 2.注意事项
- 3.一次插入多条记录
- 4.将查询结果插入到一张表中(很少用)
- (二)修改数据
- 1.语法格式
- 2.注意事项
- (三)删除数据
- 1.语法格式
- 2.注意事项
- 3.delete删除数据的原理
- 4.快速删除表中数据
- (一)插入数据
- 一、了解数据库
MySQL(上篇)
一、了解数据库
(一)数据库
英文单词DataBase,简称DB。按照一定格式存储数据的一些文件的组合。
顾名思义:存储数据的仓库,实际上就是一堆文件。这些文件中存储了具有特定格式的数据。
(二)数据库管理系统
DataBaseManagement,简称DBMS。
数据库管理系统是专门用来管理数据库中数据的,数据库管理系统可以对数据库当中的数据进行增删改查。
常见的数据库管理系统
MySQL、Oracle、MS SqlServer、DB2、sybase等…
(三)SQL
结构化查询语言
程序员需要学习SQL语句,程序员通过编写SQL语句,然后DBMS负责执行SQL语句,最终来完成数据库中数据的增删改查操作。SQL是一套标准,程序员主要学习的就是SQL语句,这个SQL在mysql中可以使用,同时在Oracle中也可以使用,在DB2中也可以使用。
分类
DQL
数据查询语言(Data Query Language)
凡是带有select关键字的都是查询语句
select…
DML
数据操作语言(Data Manipulation Language)
凡是对表当中的数据进行增删改的都是DML
insert delete update
insert 增
delete 删
update 改
这个主要是操作表中的数据data。
DDL
数据定义语言 (Data Definition Language)
凡是带有create、drop、alter的都是DDL。
DDL主要操作的是表的结构。不是表中的数据。
create:新建,等同于增
drop:删除
alter:修改
这个增删改和DML不同,这个主要是对表结构进行操作。
TCL
是事务控制语言(Transaction Control Language)
包括:
事务提交:commit;
事务回滚:rollback;
DCL
是数据控制语言。
例如:授权grant、撤销权限revoke…
(四)三者的关系
DBMS–执行–> SQL --操作–> DB
先安装数据库管理系统MySQL,然后学习SQL语句怎么写,编写SQL语句之后,DBMS对SQL语句进行执行,最终来完成数据库的数据管理。
二、MySQL常用命令
(1)退出mysql
代码语言:javascript复制exit;
(2)查看mysql中有哪些数据库
代码语言:javascript复制show databases;
mysql默认自带了4个数据库:information_schema、mysql、performance_schema、sys
(3)选择使用某个数据库
代码语言:javascript复制use mysql;
(4)创建数据库
代码语言:javascript复制create database bjpowernode;
(5)查看某个数据库下有哪些表
代码语言:javascript复制show tables;
(6)查看mysql数据库的版本号
代码语言:javascript复制select version();
(7)查看当前使用的是哪个数据库
代码语言:javascript复制select database();
(8)将sql文件中的数据导入
代码语言:javascript复制source F:JAVAMySQL_documentbjpowernode.sql #注意:路径中不要有中文!!!!
xxxx.sql这种文件被称为sql脚本文件。
sql脚本文件中编写了大量的SQL语句。
我们执行SQL语句,可以使用sql脚本文件。
在mysql当中怎么执行sql脚本文件呢?
你在实际的工作中,第一天到了公司,项目经理会给你一个xxx.sql文件,你执行这个脚本文件,你电脑上的数据库数据就有了,你想使用记事本打开sql脚本文件很有可能打不开,因为太大了,记事本内存不够,所以要使用source命令初始化这个sql脚本文件,不要试图用记事本打开后复制代码再执行。
(9)查看表结构
代码语言:javascript复制desc dept;
(10)终止一条sql命令的执行
代码语言:javascript复制/c
(11)注意事项
mysql命令 执行命令的时候结尾必须加分号 “;” ,没遇到分号不执行。除了导入sql文件的source命令
另外SQL语句不区分大小写,都行。
select 后面可以跟某个表的字段名(可以等同看做变量名),也可以跟字面量/字面值(数据)。
代码语言:javascript复制select 1000 as num from dept;
代码语言:javascript复制select '1000' as num from dept;
- 数据库中的有一条命名规范: 所有的标识符全部都是小写,单词和单词之间是使用下划线进行衔接
三、DQL语句
(一)简单查询
1.查询一个字段
代码语言:javascript复制select 字段名 from 表名;
select 和 from 都是关键字,字段名和表名都是标识符。
2.查询多个字段
使用逗号隔开“,”
代码语言:javascript复制select deptno,dname from dept; #查询部门编号和部门名
3.查询所有字段
(1)方式一
可以把每个字段都写上
代码语言:javascript复制select a,b,c,d,e,f... from tablename;
(2)方式二
可以使用*
代码语言:javascript复制select * from dept;
缺点:
- 效率低
- 可读性差。
在实际开发中不建议,可以自己玩没问题。 你可以在DOS命令窗口中想快速的看一看全表数据可以采用这种方式。
4.给查询的列起别名
(1)方式一:使用 as关键字 起别名。
代码语言:javascript复制mysql> select deptno,dname as deptname from dept;
注意:只是将显示的查询结果列名显示为deptname,原表列名还是叫:dname
记住:select语句是永远都不会进行修改操作的。(因为只负责查询)
(2)方式二:省略as关键字 用空格代替
代码语言:javascript复制select deptno,dname deptname from dept;
- 假设起别名的时候,别名里面有空格,怎么办?
select deptno,dname 'dept name' from dept; #加单引号
select deptno,dname "dept name" from dept; #加双引号
注意:在所有的数据库当中,字符串统一使用单引号括起来,单引号是标准
双引号在oracle数据库中用不了。但是在mysql中可以使用。
(二)条件查询
条件查询:不是将表中所有数据都查出来。是查询出来符合条件的。
1.格式
代码语言:javascript复制select
字段1,字段2,字段3....
from
表名
where
条件;
2.条件种类
(1)= 等于
例:查询薪资等于800的员工姓名和编号?
代码语言:javascript复制select ename,empno from emp where sal = 800;
例:查询SMITH的编号和薪资?
代码语言:javascript复制select empno,sal from emp where ename = 'SMITH'; #字符串使用单引号
(2)<> 或!= 不等于
例:查询薪资不等于800的员工姓名和编号?
代码语言:javascript复制select empno,ename from emp where sal != 800;
代码语言:javascript复制select empno,ename from emp where sal <> 800;
(3)< 小于
例:查询薪资小于2000的员工姓名、编号和薪资?
代码语言:javascript复制select empno,ename,sal from emp where sal < 2000;
(4)<= 小于等于
例:查询薪资小于等于3000的员工姓名、编号和薪资?
代码语言:javascript复制select empno,ename,sal from emp where sal <= 3000;
(5)> 大于
例:查询薪资大于3000的员工姓名、编号和薪资?
代码语言:javascript复制select empno,ename,sal from emp where sal > 3000;
(6)>= 大于等于
例:查询薪资大于等于3000的员工姓名和编号?
代码语言:javascript复制select empno,ename,sal from emp where sal >= 3000;
(7)between … and ….
两个值之间, 等同于 >= and <=
例:查询薪资在2450和3000之间的员工信息?包括2450和3000
- 方式一:>= and <= (and是并且的意思。)
select empno,ename,sal from emp where sal >= 2450 and sal <= 3000;
- 方拾二:between … and …
select
empno,ename,sal
from
emp
where
sal between 2450 and 3000;
注意:
- 使用between and的时候,必须遵循左小右大。
- between and是闭区间,包括两端的值。
(8)is null 和 is not null
- is null
例:查询哪些员工的津贴/补助为null?
代码语言:javascript复制select empno,ename,sal,comm from emp where comm is null;
外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Ls5YAwaX-1664697099999)(MySQL笔记.assets/image-20220406214157304.png)
- is not null
例:查询哪些员工的津贴/补助不为null?
代码语言:javascript复制select empno,ename,sal,comm from emp where comm is not null;
注意:在数据库当中null不能使用等号进行衡量。需要使用is null因为数据库中的null代表什么也没有,它不是一个值,所以不能使用等号衡量。
(9)and 并且
例:找出工作岗位manager并且工资大于2500的员工信息?
代码语言:javascript复制select
empno,ename,sal
from
emp
where
job = 'manager' and sal > 2500;
(10)or 或者
例:查询工作岗位是manager和salesman的员工
代码语言:javascript复制select
empno,ename,sal
from
emp
where
job = 'manager' or job = 'salesman';
and 和 or 优先级
and和or同时出现,and优先级较高。如果想让or先执行,需要加“小括号”.以后在开发中,如果不确定优先级,就加小括号就行了。
(11)in 和 not in (包含与不包含)
相当于多个or(not in 不在这个范围中)
注意:in不是一个区间,in后面跟的是具体的值。
例:查询薪资是800和5000的员工信息?
代码语言:javascript复制select empno,ename,sal from emp where sal in (800,5000); #这个不是表示800到5000都找出来,而是两个值
(12)like
称为模糊查询,支持 % 或 下划线 匹配
- %匹配任意多个字符
- 下划线:任意一个字符。
- (%是一个特殊的符号,_ 也是一个特殊符号)
例:找出名字中含有o的员工?
代码语言:javascript复制select ename from emp where ename like '%o%';
例:找出名字以T结尾的员工?
代码语言:javascript复制select ename from emp where ename like '%T';
例:找出名字以K开始的员工?
代码语言:javascript复制select ename from emp where ename like 'K%';
例:找出第二个字每是A的员工?
代码语言:javascript复制 select ename from emp where ename like '_A%';
例:找出第三个字母是R的员工?
代码语言:javascript复制 select ename from emp where ename like '__R%';
例:找出名字中有“_”的员工?
代码语言:javascript复制select ename from emp where ename like '%_%'; # 转义字符
3.排序数据
1.语法格式:
代码语言:javascript复制select
ename,sal
from
emp
order by
sal; # 默认是升序!!
指定降序: desc,指定升序: asc
2.多个字段排序
例:查询员工名字和薪资,要求按照薪资升序,如果薪资一样的话,再按照名字升序排列。
代码语言:javascript复制select
ename,sal
from
emp
order by
sal asc, ename asc; # sal在前,起主导,只有sal相等的时候,才会考虑启用ename排序。
3.根据字段位置排序(了解)
代码语言:javascript复制select ename,sal from emp order by 2; #2表示第二列,第二列是sal
不建议在开发中这么写,不建议在开发中这么写,因为不健壮。因为第二列可能会发生变化,列顺序改变之后,2就废了
4.综合案例
例:找出工资在1250到3000之间的员工信息,要求按照薪资降序排列。
代码语言:javascript复制select
empno,ename,sal
from
emp
where
sal between 1250 and 3000
order by
sal desc;
关键字顺序不能变:
代码语言:javascript复制select
...
from
...
where
...
order by
... ;
以上语句的执行顺序必须掌握:
第一步:from
第二步:where
第三步:select
第四步:order by(排序总是在最后执行!)
5.数据处理函数(单行处理函数)
数据处理函数又被称为单行处理函数,聚合函数
特点:一个输入对应一个输出。
lower 转换小写
代码语言:javascript复制select lower(ename) as ename from emp;
upper 转换大写
代码语言:javascript复制select upper(ename) as ename from emp;
substr 取子串
(substr(被截取的字符串, 起始下标,截取的长度))
代码语言:javascript复制select substr(ename, 1, 1) as ename from emp;
注意:起始下标从1开始,没有0
例:找出员工名字第一个字是A的员工信息?
代码语言:javascript复制select
empno, ename
from
emp
where
substr(ename,1,1) = 'A';
concat 拼接字符
例:将查询出来的员工的名字首字母大写?
代码语言:javascript复制select concat(upper(substr(ename,1,1)),lower(substr(ename,2,length(ename) - 1))) as result
from emp;
length 取长度
代码语言:javascript复制select length(ename) enamelength from emp;
trim 去空格
代码语言:javascript复制select * from emp where ename = trim(' KING');
round 四舍五入
代码语言:javascript复制select round(1236.567, 0) as result from emp; #保留整数位。
代码语言:javascript复制select round(1236.567, 1) as result from emp; #留1个小数
代码语言:javascript复制select round(1236.567, 2) as result from emp; #保留2个小数
代码语言:javascript复制select round(1236.567, -1) as result from emp; #保留到十位。
rand() 生成随机数
代码语言:javascript复制select round(rand()*100,0) from emp; # 100以内的随机数
ifnull 空处理函数
可以将 null 转换成一个具体值
在所有数据库当中,只要有NULL参与的数学运算,最终结果就是NULL。
注意:NULL只要参与运算,最终结果一定是NULL。
为了避免这个现象,需要使用ifnull函数。ifnull函数用法:ifnull(数据, 被当做哪个值)。如果“数据”为NULL的时候,把这个数据结构当做哪个值。
例:计算所有员工的年薪?
代码语言:javascript复制select ename, (sal comm) as yearsal from emp; #与NULL参与运算的结果都是NULL
所以使用 ifnull函数 处理如下:
代码语言:javascript复制select ename,(sal ifnull(comm,0)) as yearsal from emp; # 0为NULL时被指定的值
case…when…then…when…then…else…end
例:当员工的工作岗位是MANAGER的时候,工资上调10%,当工作岗位是SALESMAN的时候,工资上调50%,其它正常。 (注意:不修改数据库,只是将查询结果显示为工资上调)
代码语言:javascript复制select
ename,
job,
sal as oldsal,
(case job when 'MANAGER' then sal*1.1 when 'SALESMAN' then sal*1.5 else sal end) as newsal
from
emp;
str_to_date 将字符串转换成日期
将date类型转换成具有一定格式的varchar字符串类型。
代码语言:javascript复制drop table if exists t_user;
create table t_user(
id int,
name varchar(32),
birth date #生日也可以使用date日期类型
);
create table t_user(
id int,
name varchar(32),
birth char(10) #生日可以使用字符串,没问题
);
插入数据?
insert into t_user(id,name,birth) values(1, ‘zhangsan’, ‘01-10-1990’); #1990年10月1日
生日:1990-10-11 (10个字符)
出问题了:原因是类型不匹配。数据库birth是date类型,这里给了一个字符串varchar。
怎么办?可以使用str_to_date函数进行类型转换
语法格式:
代码语言:javascript复制str_to_date('字符串日期', '日期格式')
mysql的日期格式:
代码语言:javascript复制 %Y 年
%m 月
%d 日
%h 时
%i 分
%s 秒
代码语言:javascript复制insert into t_user(id,name,birth) values(1, 'zhangsan', str_to_date('01-10-1990','%d-%m-%Y'));
- str_to_date函数可以把字符串varchar转换成日期date类型数据, 通常使用在插入insert方面,因为插入的时候需要一个日期类型的数据, 需要通过该函数将字符串转换成date。
- 如果你提供的日期字符串是这个格式,str_to_date函数就不需要了!!! %Y-%m-%d
insert into t_user(id,name,birth) values(2, 'lisi', '1990-10-01');
date_format
这个函数可以将日期类型转换成特定格式的字符串。
代码语言:javascript复制select id,name,date_format(birth, '%m/%d/%Y') as birth from t_user;
- 语法格式 date_format(日期类型数据, ‘日期格式’) 这个函数通常使用在查询日期方面。设置展示的日期格式。
select id,name,birth from t_user;
以上的SQL语句实际上是进行了默认的日期格式化,
自动将数据库中的date类型转换成varchar类型。
并且采用的格式是mysql默认的日期格式:‘%Y-%m-%d’
format 设置千分位
代码语言:javascript复制select ename,format(sal, '$999,999') as sal from emp;
now 获取系统当前日期时间
代码语言:javascript复制create table t_date(create_time datetime);
insert into t_date(create_time) values(now());
select * from t_date;
timestampdiff 计算两个日期的时间差
TimeStampDiff(间隔类型, 前一个日期, 后一个日期)
间隔类型:
SECOND 秒,
MINUTE 分钟,
HOUR 小时,
DAY 天,
WEEK 星期
MONTH 月,
QUARTER 季度,
YEAR 年
6.分组函数(多行处理函数)
多行处理函数的特点:输入多行,最终输出一行
(1)种类(5个)
- count 计数
- sum求和
- avg求平均数
- max求最大值
- min求最小值
例:找出最高工资?
代码语言:javascript复制select ename,max(sal) from emp;
例:找出最低工资?
代码语言:javascript复制select ename,min(sal) from emp;
例:计算工资的和?
代码语言:javascript复制select sum(sal) from emp;
例:计算平均工资?
代码语言:javascript复制select avg(sal) from emp;
例:计算员工的数量?
代码语言:javascript复制select count(ename) from emp;
(2)注意事项
分组函数在使用的时候必须先进行分组,然后才能使用,如果你没有对数据进行分组,整张表默认为一组
分组函数自动忽略NULL,你不需要提前对NULL处理
分组函数中count(*)和count(具体字段)有什么区别?
- count(具体字段):表示统计该字段下所有不为NULL的元素的总数。
- count(*):统计表当中的总行数。(只要有一行数据count则 )因为每一行记录不可能都为NULL,一行数据中有一列不为NULL,则这行数据就是有效的。
分组函数不能够直接使用在where子句中。
所有的分组函数可以组合起来一起用。
代码语言:javascript复制select sum(sal),min(sal),max(sal),avg(sal),count(*) from emp;
(三)分组查询(重要)
(1)语法格式:
代码语言:javascript复制select
...
from
...
group by
...
计算每个部门的工资和?
计算每个工作岗位的平均薪资?
(2)执行顺序
代码语言:javascript复制select
...
from
...
where
...
group by
...
order by
...
- 以上关键字的顺序不能颠倒,需要记忆。 执行顺序是什么? 1.from 2.where 3.group by 4.select 5.order by
- 为什么分组函数不能直接使用在where后面? select ename,sal from emp where sal > min(sal); #报错 where执行的时候,还没有分组。所以where后面不能出现分组函数。
- select sum(sal) from emp; 这个没有分组,为啥sum()函数可以用呢? 因为select在group by之后执行。
例:找出每个工作岗位的工资和?
实现思路:按照工作岗位分组,然后求和
代码语言:javascript复制select
job, sum(sal) as '工资总和'
from
emp
group by
job;
外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0DaXChB6-1664697100012)(MySQL笔记.assets/image-20220407203230338.png)
顺序:先从emp表中查询数据,将这个表分组,然后对每一组数据进行求和sum(sal)
- select ename,job,sum(sal) from emp group by job; 以上语句在mysql中可以执行,但是毫无意义。 以上语句在oracle中执行报错。 oracle语法比mysql的语法严格。(mysql的语法相对来说松散一些)
- 重点结论: 在一条select语句当中,如果有group by语句的话, select后面只能跟:参加分组的字段,以及分组函数。 其他的一律不跟
例:找出每个工作岗位的最高工资?
实现思路:先查询emp表然后对工作岗位分组,然后查询最高工资
代码语言:javascript复制select
job,max(sal)
from
emp
group by
job;
例:找出每个部门,不同工作岗位的最高工资?
技巧:两个字段联合成1个字段看(两个字段联合分组)
代码语言:javascript复制select
job, deptno,max(sal)
from
emp
group by
deptno,job;
外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2lx19QsG-1664697100012)(MySQL笔记.assets/image-20220407212711309.png)
(3)having条件
使用having可以对分完组之后的数据进一步过滤。
having不能单独使用,having不能代替where,having必须和group by一起使用
例:找出每个部门最高薪资,要求显示最高薪资大于3000的?
第一步:找出每个部门最高薪资
代码语言:javascript复制select
deptno,max(sal)
from
emp
group by
deptno;
第二步:对结果进行筛选,显示最高薪资大于3000的
代码语言:javascript复制select
deptno,max(sal)
from
emp
group by
deptno
having
max(sal) > 3000;
思考:以上的sql语句执行效率是不是低?
比较低,实际上可以这样考虑:现将大于3000的都找出来,然后分组。
优化策略:where和having优先选择where,where完成不了的,再选择having
代码语言:javascript复制select
deptno,max(sal)
from
emp
where
sal > 3000
group by
deptno;
例:找出每个部门平均薪资,要求显示平均薪资高于2500的。
- 这题就不能用where,因为平均值只能在分组之后才能计算,而where是在分组之前进行的,而只有having是在分组之后进行的
select
deptno,avg(sal)
from
emp
group by
deptno
having
avg(sal) > 2500;
综合案例:
找出每个岗位的平均薪资,要求显示平均薪资大于1500的,除了MANAGER岗位之外,要求按照平均薪资降序排列
代码语言:javascript复制select
job,avg(sal)
from
emp
where
job != 'MANAGER' #也可以写成:job <> 'MANAGER'
group by
job
having
avg(sal) > 1500
order by
avg(sal) desc;
(4)distinct
把查询结果去除重复记录
注意:原表数据不会被修改,只是查询结果去重。
- distinct只能出现在所有字段的最前方。
select distinct job from emp;
- distinct出现在job,deptno两个字段之前,表示两个字段联合起来去重。
select distinct job,deptno from emp;
例:统计工作岗位的数量
代码语言:javascript复制select count(distinct job) from emp;
到这里单表查询结束
(四)连接查询(非常重要)
1.概述
什么是连接查询?
emp表和dept表联合起来查询数据,从emp表中取出员工名字,从dept表中取部门名字。这种跨表查询,多张表联合起来查询数据,被称为连接查询
2.连接查询的分类
- 根据语法的年代分类: SQL92:1992年的时候出现的语法 SQL99:1999年的时候出现的语法
- 根据表连接的方式分类: (1)内连接: 等值连接 非等值连接 自连接 (2)外连接: 左外连接(左连接) 右外连接(右连接) (3)全连接(不讲)
3.笛卡尔积现象
当两张表进行连接查询,**没有任何条件限制的时候,**最终查询结果条数,是两张表条数的成绩,这种现象被称为:笛卡尔积现象(笛卡尔发现的,这是一个数学现象)
- 怎么避免笛卡尔积现象? 连接时加条件,满足这个条件的记录被筛选出来!
select
ename,dname
from
emp,dept
where
emp.deptno = dept.deptno;
- 思考:最终查询的结果条数只有14条,但是匹配的过程中,匹配的次数减少了吗? 还是56次,只不过进行了四选一。次数没有减少
- 改进代码,提高效率
select
emp.ename,dept.dname #这里能增加查询的效率
from
emp ,dept
where
emp.deptno = dept.deptno;
- 给表起别名(这里的写法是SQL92的写法)
select
e.ename,d.dname
from
emp e,dept d
where
e.deptno = d.deptno;
注意:通过笛卡尔积现象,标的连接次数越多效率越低,尽量避免表的连接次数
4.内连接
(1)等值连接
- 因为连接条件 e.deptno = d.deptno 是等量关系所以被称为等值连接
例:查询每个员工所在部门名称,显示员工名和部门名?
emp e和dept d表进行连接。条件是:e.deptno = d.deptno
- SQL92语法:
select
e.ename,d.dname
from
emp e,dept d
where
e.deptno = d.deptno;
SQL92缺点:结构不清晰,表的连接条件,和后期进一步筛选的条件,都放到了where后面
- SQL99语法:
select
e.ename,d.dname
from
emp e
inner join #此处inner是可以省略的
dept d
on
e.deptno = d.deptno;
SQL99优点:表连接的条件是独立的,连接之后,如果还需要进一步筛选,再往后继续添加where
- SQL99语法格式:
select
...
from
表a
join
表b
on
a和b的连接条件
where
筛选条件
(2)非等值连接
- 因为条件不是一个等量关系,称为非等值连接
例:找出每个员工的薪资等级,要求显示员工名、薪资、薪资等级?
(员工表)
(工资等级表)
代码语言:javascript复制select
e.ename,e.sal,s.grade
from
emp e
join
salgrade s
on
e.sal between s.losal and s.hisal;
代码语言:javascript复制select
e.ename,e.sal,s.grade
from
emp e
inner join #此处inner是可以省略的
salgrade s
on
e.sal between s.losal and s.hisal;
(3)自连接
一张表看成两张表
例:查询员工的上级领导,要求显示员工名和对应的领导名?
技巧:一张表看成两张表
emp a 员工表
emp b 领导表
代码语言:javascript复制select
a.ename as '员工名' ,b.ename as '领导名'
from
emp a
join
emp b
on
a.mgr = b.empno;
这里只有13记录,因为KING没有领导
5.外连接
内连接:(a和b两张表没有主次关系,平等的)
代码语言:javascript复制select
e.ename,d.dname
from
emp e
join
dept d
on
e.deptno = d.deptno; #内连接特点:完全能够匹配的上这个条件的数据查询出来
- 外连接(右外连接)
select
e.ename,d.dname
from
emp e
right outer join #outer可以省略 写上就是可读性强
dept d
on
e.deptno = d.deptno;
right 代表什么:表示将join关键字右边的这张表看成主表,主要是为了将这张表的数据全部查询出来,捎带着关联查询左边的表。
在外连接当中,两张表连接,产生了主次关系。
- 左外连接(左连接)
select
e.ename,d.dname
from
dept d
left outer join #outer可以省略,写上就是可读性强
emp e
on
e.deptno = d.deptno;
- 带有right的是右外连接,又叫右连接
- 带有left的是左外连接,又叫左连接
- 任何一个右连接都有左连接的写法
- 任何一个左连接都有右连接的写法
6.内连接与外连接的区别
- 写了left 和 right 的一定是外连接
- inner 和 outer都可以省略
思考:外连接的查询结果条数一定是 >= 内连接的查询结果条数?
正确
例:查询每个员工的上级领导,要求显示所有员工的名字和领导名?
代码语言:javascript复制select
a.ename '员工名',b.ename '领导名'
from
emp a
left join
emp b
on
a.mgr = b.empno; #这行代码的意思是:员工表每个员工的领导编号 = 员工表的员工号(相当于是领导的员工编号)
#所以就可以把a表看作是员工表,b表看作是领导表
此处king的信息用外连接也查出来了,而使用内连接就差不出来
7.全连接(了解)
全连接就是连接的表全是主表
8.多张表连接
语法:
代码语言:javascript复制select
...
from
a
join
b
on
a和b连接的条件
right join
c
on
a和c的连接条件
left join
d
on
a和d的连接条件
...
- 一条SQL中内连接和外连接可以混合。都可以出现。
例:找出每个员工的部门名称以及工资等级,要求显示员工名,部门名,薪资,薪资等级?
代码语言:javascript复制select
e.ename '员工名',d.dname '部门名',e.sal '薪资',s.grade '薪资等级'
from
emp e
join
dept d
on
e.deptno = d.deptno
join
salgrade s
on
e.sal between s.losal and s.hisal;
案例升级:找出每个员工的部门名称以及工资等级,还有上级领导。
要求显示员工名、领导名、部门名、薪资、薪资等级?
代码语言:javascript复制select
e.ename '员工名',l.ename '领导名',d.dname '部门名',e.sal '薪资', s.grade '薪资等级'
from
emp e
join
dept d
on
e.deptno = d.deptno
join
salgrade s
on
e.sal between s.losal and s.hisal
left join
emp l
on
e.mgr = l.empno;
(五)子查询
1.概述
什么是子查询?
select语句中嵌套select语句,被嵌套的select语句称为子查询
子查询都可以出现在哪里?
代码语言:javascript复制select
..(select).
from
..(select).
where
..(select).
2.where子句中的子查询
例:找出比最低工资高的员工的薪资?
实现思路:
第一步:查询最低工资是多少?
代码语言:javascript复制select min(sal) from emp;
代码语言:javascript复制第二步:找出 > 800的员工及薪资?
代码语言:javascript复制select ename,sal from emp where sal > 800;
第三步:合并
代码语言:javascript复制select ename,sal from emp where sal > (select min(sal) from emp);
3.from中的子查询
注意:from后面的子查询,可以将子查询的查询结果当做一张临时表。(技巧)
例:找出每个岗位的平均工资的薪资等级。
实现思路:
第一步:查询每个岗位的平均薪资?
代码语言:javascript复制select
job, avg(sal)
from
emp
group by
job;
第二步:将查询结果当做一张表进行查询,查询这个结果的薪资等级?
代码语言:javascript复制select
t.job,t.avgsal,s.grade '薪资等级'
from(
select
job, avg(sal) as avgsal #这里数据处理函数不取别名的话,程序会报错,说avg(sal)不存在!!!
from
emp
group by
job
) as t
join
salgrade s
on
t.avgsal between s.losal and s.hisal;
4.select后面的子查询(了解)
例:找出每个员工的部门名称,要求显示员工名,部门名?
代码语言:javascript复制select e.ename,(select d.dname from dept d where e.deptno = d.deptno) as dname from emp e;
注意:对于select后面的子查询来说,这个子查询只能一次返回一个结果,否则就会报错如下:
错误:ERROR 1242 (21000): Subquery returns more than 1 row
5.union合并查询结果集
例:查询工作岗位是MANAGER和SALESMAN的员工?
代码语言:javascript复制select ename,job from emp where job = 'MANAGER' or job = 'SALESMAN';
代码语言:javascript复制select ename,job from emp where job in('MANAGER','SALESMAN');
使用union进行查询结果集合并:
代码语言:javascript复制select ename,job from emp where job = 'MANAGER'
union
select ename,job from emp where job = 'SALESMAN';
- union的效率要高一些,对于表连接来说,每连接一次新表,则匹配的次数满足笛卡尔积,成倍的翻。。。
- 但是union可以减少匹配次数。在减少匹配次数的情况下,还可以完成两个结果集的拼接。
- a 连接 b 连接 c a 10条记录 b 10条记录 c 10条记录 匹配次数:1000 a 连接 b 一个结果:10*10 -->100次 a 连接 c 一个结果:10*10 -->100次 使用union的话是:100次 100次 = 200次
union使用的注意事项:
- union在进行结果集合并的时候,要求两个结果集的列数相同。 select ename,job from emp where job = ‘MANAGER’ union select ename from emp where job = ‘SALESMAN’; #会报错
- 结果集合合并列和列的数据类型也要一致 (MySQL可以,但是Oracle语法严格会报错) select ename,job from emp where job = ‘MANAGER’ union select ename,sal from emp where job = ‘SALESMAN’;
6.limit
limit的作用
将查询结果集的一部分取出来。通常使用在分页查询当中。
百度默认:10条记录。
分页的作用是为了提高用户的体验,因为一次全部都查出来,用户体验差。可以一页一页翻页看。
limit的使用
**完整用法:**limit startIndex, length
startIndex是起始下标,length是长度。
**缺省用法:**limit 5 这是取前五
例:按照薪资降序,取出排名前五的的员工?
代码语言:javascript复制select
ename,sal
from
emp
order by
sal desc
limit 5; #取前五
代码语言:javascript复制select
ename,sal
from
emp
order by
sal desc
limit 0,5; #取前五
- limit 代码顺序 mysql中limit在order by 之后执行!!!!
例:取出工资排名在3-5名的员工?
代码语言:javascript复制select
ename,sal
from
emp
order by
sal desc
limit
2,3; #[3-5]名 2是起始位置,3是长度
分页
每页显示3条记录
第1页:limit 0,3 0 1 2
第2页:limit 3,3 3 4 5
第3页:limit 6,3 6 7 8
第4页:limit 9,3 9 10 11
每页显示pageSize条记录
第pageNo页:limit (pageNo - 1) * pageSize , pageSize (公式)
代码语言:javascript复制public static void main(String[] args){
// 用户提交过来一个页码,以及每页显示的记录条数
int pageNo = 5; //第5页
int pageSize = 10; //每页显示10条
int startIndex = (pageNo - 1) * pageSize;
String sql = "select ...limit " startIndex ", " pageSize;
}
(六)DQL总结
代码语言:javascript复制select
...
from
...
where
...
group by
...
having
...
order by
...
limit
...
执行顺序:
- from
- where
- group by
- having
- select
- order by
- limit
四、DDL语句
DDL包括:create drop alter
(一)表的创建(建表)
1.语法格式
代码语言:javascript复制 create table 表名(字段名1 数据类型, 字段名2 数据类型, 字段名3 数据类型);
代码语言:javascript复制create table 表名(
字段名1 数据类型,
字段名2 数据类型,
字段名3 数据类型
);
表名:建议以t_ 或者 tbl_开始,可读性强。见名知意。
字段名:见名知意。
表名和字段名都属于标识符。
2.mysql中的数据类型
很多数据类型,我们只需要掌握一些常见的数据类型即可。
(1)varchar(最长255)
可变长度的字符串
比较智能,节省空间。
会根据实际的数据长度动态分配空间。
优点:节省空间
缺点:需要动态分配空间,速度慢。
(2)char(最长255)
定长字符串
不管实际的数据长度是多少。
分配固定长度的空间去存储数据。
使用不恰当的时候,可能会导致空间的浪费。
优点:不需要动态分配空间,速度快。
缺点:使用不当可能会导致空间的浪费。
- varchar 和 char 我们应该怎么选择? 性别字段你选什么?因为性别是固定长度的字符串,所以选择char。 姓名字段你选什么?每一个人的名字长度不同,所以选择varchar。
(3)int(最长11)
数字中的整数型。等同于java的int。
(4)bigint
数字中的长整型。等同于java中的long。
(5)float
单精度浮点型数据
(6)double
双精度浮点型数据
(7)date
短日期类型
(8)datetime
长日期类型
- date和datetime两个类型的区别? date是短日期:只包括年月日信息。 datetime是长日期:包括年月日时分秒信息。 mysql短日期默认格式:%Y-%m-%d mysql长日期默认格式:%Y-%m-%d %h:%i:%s (9)clob
字符大对象
最多可以存储4G的字符串。
比如:存储一篇文章,存储一个说明。
超过255个字符的都要采用CLOB字符大对象来存储。
Character Large OBject:CLOB
(10)blob
二进制大对象
Binary Large OBject
专门用来存储图片、声音、视频等流媒体数据。
往BLOB类型的字段上插入数据的时候,例如插入一个图片、视频等,
你需要使用IO流才行
3.创建一个学生表
学号、姓名、年龄、性别、邮箱地址
代码语言:javascript复制create table t_student(
no int,
name varchar(32),
sex char(1),
age int(3),
email varchar(255)
);
4.给字段设置默认值
代码语言:javascript复制create table t_student(
no int,
name varchar(32),
sex char(1) default '男', #使用default设置默认值
age int(3),
email varchar(255)
);
5.快速创建表(了解)
原理:将一个查询结果当做一张表新建
这个可以完成表的快速复制
表创建出来,同时表中的数据也存在了
代码语言:javascript复制create table emp2 as select * from emp; #as可写可不写
(二)表的删除
1.语法格式
代码语言:javascript复制drop table 表名;
2.注意事项
当这张表不存在的话会报错!
所以将删表格式改为:
代码语言:javascript复制drop table if exists 表名;
(三)对表结构的增删改
- 什么是对表结构的修改? 添加一个字段,删除一个字段,修改一个字段!!
第一:在实际的开发中,需求一旦确定后,表一旦设计好之后,很少的进行表结构的修改。因为开发进行中的时候,修改表结构,成本比较高。修改表的结构,对应的java代码就需要进行大量的修改。成本是比较高的。这个责任应该由设计人员来承担!
第二:由于修改表结构的操作很少,所以我们不需要掌握,如果有一天真的要修改表结构,你可以使用工具!
修改表结构的操作是不许需要写到java程序中的。实际上也不是java程序员的范畴
- 对表结构的修改需要使用:alter
修改表名
代码语言:javascript复制alter table goods2 rename to shop_db.goods2;
字段操作
alter添加字段在指定位置
代码语言:javascript复制ALTER TABLE goods add tax int(10) AFTER price;
alter删除字段
代码语言:javascript复制ALTER TABLE goods drop tax;
alter修改字段类型及名称
如果需要修改字段类型及名称, 你可以在ALTER命令中使用 MODIFY 或 CHANGE 子句 。
代码语言:javascript复制alter table goods modify c varchar(10);
使用 CHANGE 子句, 语法有很大的不同。 在 CHANGE 关键字之后,紧跟着的是你要修改的字段名,然后指定新字段名及类型
代码语言:javascript复制alter table goods change tax tax1 bigint
alter修改数据库字符集
代码语言:javascript复制alter database 数据库名 character set utf8;
alter修改表字符集
代码语言:javascript复制ALTER TABLE 表名 DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;
alter修改列字符集
代码语言:javascript复制ALTER TABLE 表名 CHANGE 列名 列名 VARCHAR( 100 ) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL;
(四)约束(非常重要)
1.概述
- 什么是约束? 约束对应的英语单词: constraint 在创建表的时候,我们可以给表中的字段加上一些约束,来保证这个表中数据的完整性、有效性!
- 约束的作用就是为了保证:表中的数据有效!
2.约束的分类
非空约束:not null
唯一性约束: unique
主键约束: primary key (简称PK)
外键约束:foreign key(简称FK)
检查约束:check(mysql不支持,oracle支持)
3.非空约束:not null
非空约束not null约束的字段不能为NULL
当你插入数据的时候,如果你插入的数据的字段是非空的,你就必须要插入这个字段的数据,否则的就会报错。
代码语言:javascript复制drop table if exists t_vip;
create table t_vip(
id int,
name varchar(255) not null # not null只有列级约束,没有表级约束!
);
4.唯一性约束: unique
唯一性约束unique约束的字段不能重复,但是可以为NULL。
代码语言:javascript复制drop table if exists t_vip;
create table t_vip(
id int,
name varchar(255) unique,
email varchar(255)
);
insert into t_vip(id) values(1); # name字段虽然被unique约束了,但是可以为NULL
insert into t_vip(id) values(2);
新需求:name和email两个字段联合起来具有唯一性
以下这样的数据是符合我“新需求”的:
代码语言:javascript复制insert into t_vip(id,name,email) values(1,'zhangsan','zhangsan@123.com');
insert into t_vip(id,name,email) values(2,'zhangsan','zhangsan@sina.com');
insert into t_vip(id,name,email) values(2,'sada','zhangsan@sina.com');
如何做到联合唯一约束?
代码语言:javascript复制drop table if exists t_vip;
create table t_vip(
id int,
name varchar(255),
email varchar(255),
unique(name,email) # 约束没有添加在列的后面,这种约束被称为表级约束。
);
- 什么时候使用表级约束呢? 需要给多个字段联合起来添加某一个约束的时候,需要使用表级约束。
- unique和not null可以联合吗? 在mysql当中,如果一个字段同时被not null和unique约束的话,该字段自动变成主键字段。 在oracle中不是这样的
5.主键约束: primary key
简称:PK
主键约束的相关术语?
主键约束:就是一种约束。
主键字段:该字段上添加了主键约束,这样的字段叫做:主键字段
主键值:主键字段中的每一个值都叫做:主键值。
什么是主键?有啥用?
主键值是每一行记录的唯一标识。
主键值是每一行记录的身份证号!!!
记住:任何一张表都应该有主键,没有主键,表无效!!
**主键的特征:not null unique(**主键值不能是NULL,同时也不能重复!)
怎么给一张表添加主键约束呢?
代码语言:javascript复制drop table if exists t_vip;
# 1个字段做主键,叫做:单一主键
create table t_vip(
id int primary key, #列级约束
name varchar(255)
);
可以这样添加主键吗,使用表级约束?
代码语言:javascript复制drop table if exists t_vip;
create table t_vip(
id int primary key, #列级约束
name varchar(255),
primary key(id)
);
表级约束主要是给多个字段联合起来添加约束
代码语言:javascript复制drop table if exists t_vip;
// id和name联合起来做主键:复合主键!!!!
create table t_vip(
id int,
name varchar(255),
email varchar(255),
primary key(id,name)
);
在实际开发中不建议使用:复合主键。建议使用单一主键!
因为主键值存在的意义就是这行记录的身份证号,只要意义达到即可,单一主键可以做到。
复合主键比较复杂,不建议使用!!!
一张表只能添加一个主键
主键值建议使用:
int
bigint
char
等类型。
不建议使用:varchar来做主键。主键值一般都是数字,一般都是定长的!
主键除了:单一主键和复合主键之外,还可以这样进行分类:
自然主键:主键值是一个自然数,和业务没关系。
业务主键:主键值和业务紧密关联,例如拿银行卡账号做主键值。这就是业务主键!
在实际开发中使用业务主键多,还是使用自然主键多一些?
自然主键使用比较多,因为主键只要做到不重复就行,不需要有意义。
业务主键不好,因为主键一旦和业务挂钩,那么当业务发生变动的时候,
可能会影响到主键值,所以业务主键不建议使用。尽量使用自然主键。
在mysql当中,有一种机制,可以帮助我们自动维护一个主键值
代码语言:javascript复制drop table if exists t_vip;
create table t_vip(
id int primary key auto_increment, //auto_increment表示自增,从1开始,以1递增!
name varchar(255)
);
6.外键约束:foreign key
- 外键约束涉及到的相关术语: 外键约束:一种约束( foreign key) 外键字段:该字段上添加了外键约束 外键值:外键字段当中的每一个值。
- 外键约束的作用 但第一张表的字段没有任何约束的时候,可能会导致数据无效,原本cno只能取100,101但可能出现一个102,所以为了保证cno字段都是第二张表中的cno的100和101,需要给cno字段添加外键约束 那么cno字段就是外键字段,cno字段中的每一个值都是外键值
- 当使用了外键约束的时候两张表就有了父子关系,被引用的是父表,引用的是子表
- 删除的顺序:先删子表再删父表
- 创建表的顺序:先创建父表,再创建子表
- 删除数据的顺序:先删子,再删父
- 子表中的外键引用的父表中的某个字段,被引用的这个字段必须是主键吗? 不一定是主键,但至少具有unique约束
- 测试:外键可以为NULL吗?
- 外键值可以为NULL。
五、DML语句
(一)插入数据
1.语法格式
代码语言:javascript复制insert into 表名(字段名1,字段名2,字段名3...) values(值1,值2,值3);
注意:字段名和值要一 一对应。什么是一一对应?
数量要对应。数据类型要对应。
例:向学生表中插入数据
代码语言:javascript复制insert into t_student(no,name,sex,age,email) values(1,'啵啵鱼','男',20,'boboyu@qq.com');
下面这样也可以:(只要数据和字段名对应就可以)
代码语言:javascript复制insert into t_student(name,no,sex,age,email) values('酸菜鱼',2,'男',20,'suancaiyu@qq.com');
insert语句中的“字段名”可以省略吗?可以。
insert into t_student values(2); //错误的
注意:前面的字段名省略的话,等于都写上了!所以值也要都写上!
代码语言:javascript复制 insert into t_student values(2, '啵啵鱼', '男', 20, 'boboyu@qq.com');
2.注意事项
- insert如果直插入了一个字段的数据,那么其他字段的数据就会为NULL
insert into t_student(no) values(1);
- insert语句插入完数据后就只能修改数据,不能向已经插入的数据中继续插入数据。
insert into t_student(name) values('烤鱼');
3.一次插入多条记录
代码语言:javascript复制 insert into t_user(id,name,birth) values
(1,'zs','1980-10-11'),
(2,'lisi','1981-10-11'),
(3,'wangwu','1982-10-11');
4.将查询结果插入到一张表中(很少用)
emp_bak插入前:
代码语言:javascript复制create table dept_bak as select * from dept; #as可写可不写
将查询结果插入到emp_bak中:
代码语言:javascript复制insert into dept_bak select * from dept; #这里不能写as
(二)修改数据
1.语法格式
代码语言:javascript复制update 表名 set 字段名1=值1,字段名2=值2,字段名3=值3... where 条件;
例:t_user表修改前:
修改后:
代码语言:javascript复制update t_user set name = '酸菜鱼', birth = '2020-1-1' where id = 1;
2.注意事项
- 没有条件限制会导致更改的字段下面全部的数据全都更新。
update t_user set name = '啵啵鱼';
(三)删除数据
1.语法格式
代码语言:javascript复制delete from 表名 where 条件;
删除前:
删除后:
代码语言:javascript复制delete from t_user where id = 2;
2.注意事项
- 没有条件,整张表的数据会全部删除!
delete from t_user; #删除所有
3.delete删除数据的原理
表中数据被删除了,但是这个数据在硬盘上的真实存储空间不会被释放!
这种删除缺点是:删除效率比较低。
这种删除优点是:支持回滚,后悔了可以再恢复数据!!!
4.快速删除表中数据
- truncate语句删除数据的原理: 这种删除效率比较高,表被一次截断,物理删除。
这种删除缺点:不支持回滚。
这种删除优点:快速。
用法:(这种操作属于DDL操作。)
代码语言:javascript复制truncate table dept_bak;
大表非常大,上亿条记录
删除的时候,使用delete,也许需要执行1个小时才能删除完!效率较低。
可以选择使用truncate删除表中的数据。只需要不到1秒钟的时间就删除结束。效率较高。
但是使用truncate之前,必须仔细询问客户是否真的要删除,并警告删除之后不可恢复!