1.基础概念
1.1 相关概念与常用命令
数据库的好处
1.持久化数据到本地
2.可以实现结构化查询,方便管理
常见概念
1、DB:数据库,保存一组有组织的数据的容器
2、DBMS:数据库管理系统,又称为数据库软件(产品),用于管理DB中的数据
3、SQL: 结构化查询语言,用于和DBMS通信的语言
数据库存储数据的特点
1、将数据放到表中,表再放到库中
2、一个数据库中可以有多个表,每个表都有一个的名字,用来标识自己。表名具有唯一性。
3、表具有一些特性,这些特性定义了数据在表中如何存储,类似java中“类”的设计。
4、表由列组成,我们也称为字段。所有表都是由一个或多个列组成的,每一列类似java 中的”属性”
5、表中的数据是按行存储的,每一行类似于java中的“对象”
MySQL的启动和停止
启动:net start 服务名(例如:net start mysql80)
停止:net stop 服务名(例如:net stop mysql80)
MySQL的登录和退出
登录:mysql -h 主机名 -P 端口号 -u 用户名 -p密码
(注意:-p和密码中间不能加空格)
(例如:mysql 【-h localhost P 3306】 -u root -p564445 ,若是登录本地的,【】内的可以不写)
退出:exit 或 ctl+c
MySQL常见命令
show databases; #查看所有的数据库
use 库名; #打开指定 的库
show tables ; #显示库中的所有表
show tables from 库名; #显示指定库中的所有表
create table 表名(
字段名 字段类型,
字段名 字段类型
); 创建表
desc 表名; #查看指定表的结构
select * from 表名; #显示表中的所有数据
查询语句
select 字段名 from 表名;
select 字段名1,字段名2,...... from 表名;
select * from 表名;
select 常量值;(注意:字符型和日期型的常量值要用单引号括起来,数值型不需要)
select 函数名;
select 表达式;
select 数值+数值; /*结果为数值*/
select 字符+数值; /*试图将字符转换成数值,转换成功则继续运算,转换不成功则把字符当成成0再运算*/
select null+值; /*结果都为null*/
#别名
select 字段名 as 别名 from 表名;
select 字段名 别名 from 表名; /*可直接用空格代替as*/
#去重
select distinct 字段名 from 表名;
#concat函数
select concat(字符1,字符2,......) from 表名;
#ifnull函数
#判断某字段或表达式是否为null,如果为null,返回指定的值(比如指定0),否则返回原本的值
select ifnull(字符, 0) from 表名;
#isnull
#判断某字段或表达式是否为null,是则返回1,不是则返回0
select 字符1 from 表名 where 字符1 is null;
select 字符1 from 表名 where 字符1 is not null;
条件运算符
>
<
>=
<=
= ,<=> 安全等于
!= ,<>
逻辑运算符
and(&&):两个条件如果同时成立,结果为true,否则为false
or(||):两个条件只要有一个成立,结果为true,否则为false
not(!):如果条件成立,则not后为false,否则为true
模糊查询
like
between and
in
is null
排序查询
#语法
select
要查询的东西
from
表
where
条件
order by 排序的字段|表达式|函数|别名 【asc|desc】
(默认升序)
#实践代码-----------------------------
select * from employees order by salary desc;
select * from employees order by salary asc;
select *
from employees
where department_id >= 90
order by hiredate asc;
#按年薪的高低显示员工的信息和年薪(按表达式排序)
select *, salary*12*(1+ifnull(commission_pct, 0)) as 年薪
from employees
#order by salary*12*(1+ifnull(commission_pct, 0)) desc;
order by 年薪 desc;
#按姓名长度显示员工的姓名和工资【按函数排序】
select length(last_name) as 字节长度, last_name, salary
from employees
order by 字节长度 desc;
#查询员工信息,先按工资什序,再按员工编号降序【按多个字段排序】
select *
from employees
order by salary asc, employee_id desc;
1.2 实践代码
use myemployees;
select * from employees;
select first_name from employees;
select first_name as hhh from employees;
select first_name hhh from employees;
select distinct department_id from employees;
select ifnull(commission_pct, 0) as '奖金率', commission_pct from employees;
select concat(first_name,'___' ,last_name,'___',ifnull(commission_pct, 0)) as output from employees;
select 100;
select 'xym';
select 100*20 as resulet;
select version();
/*
select
查询列表
from
表名
where
筛选条件;
*/
select * from employees where salary>12000;
select last_name, department_id from employees where department_id <> 90;
select last_name, salary, commission_pct
from employees
where salary >= 10000 and salary <= 20000;
select *
from employees
where not(department_id < 90 or department_id>110)
or salary > 15000;
/*通配符:%任意多个字符
_任意单个字符
*/
select * from employees where last_name like '%a%';
select * from employees where last_name like '_e_l';
select *
from employees
where last_name
like '_$_%' escape '$';*/ /*查询第二个字符为_的员工,转义*/
select *
from employees
where employee_id
between 100 and 120; /*包含临界值(闭区间),不能颠倒大小*/
select last_name, job_id
from employees
#where job_id='IT_PROT' or job_id= 'AD_VP' or job_id = 'AD_PRES';
where job_id in('IT_PROT','AD_VP','AD_PRES')
/*
is null:仅可以判断 null
<=>:既可以判断 null,又可以判断数值
*/
select last_name, commission_pct
from employees
#where commission_pct is null;
where commission_pct is not null;
select last_name, commission_pct
from employees
where commission_pct <=> null; /*安全等于*/
select last_name, commission_pct, salary
from employees
where salary <=> 12000; /*安全等于*/
2.函数
#语法
select 函数名() from 表
2.1 单行函数
字符函数
/*concat拼接
substr截取子串
upper转换成大写
lower转换成小写
trim去前后指定的空格和字符
ltrim去左边空格
rtrim去右边空格
replace替换
lpad左填充
rpad右填充
instr返回子串第一次出现的索引
length 获取字节个数
*/
select length('length');
select upper('select');
select lower('WERTY');
select concat(upper(last_name), lower(first_name)) 姓名 from employees;
select substr('李莫愁神雕侠侣', 4) as aa; #索引从1开始
select substr('李莫愁神雕侠侣', 4, 2) as aa; #后面的2表示字符长度
select concat(substr(last_name, 1, 1), '_', lower(substr(last_name, 2))) aa from employees;
select instr('倚天屠龙记屠龙记', '屠龙记') as aa; #找不到返回0
select length(trim(' 子怡 ')) as aa;
select trim('a' from 'aaa子怡aaaa') as aa;
select lpad('你好', 10, '*') output;
select rpad('你好', 10, '*') output;
select replace('张无忌_周芷若_周芷若_周芷若', '周芷若', '赵敏') aa;
数学函数
/*round 四舍五入
rand 随机数
floor向下取整
ceil向上取整
mod取余
truncate截断*/
select round(-1.35);
select round(1.5664, 2);
select ceil(1.564); #2
select ceil(1); #1
select floor(1.564); #1
select floor(1); #1
select truncate(1.6932, 2);
select mod(10, 3); #1
select mod(-10, 3); #-1
select mod(10, -3); #1
select mod(-10, -3); #-1 总结:符号和被除数保持一致
日期函数
/*now当前系统日期+时间
curdate当前系统日期
curtime当前系统时间
datediff(date1, date2)日期之差date1-date2
str_to_date 将字符转换成日期
date_format将日期转换成字符
*/
select now();
select curdate();
select curtime();
select year(now()) 年, month(now()) 月;
select year('1998-8-18') 年;
select monthname(now()) 月;
select datediff(now(), '1998-10-8');
#str_to_data:将日期格式的字符转换成指定格式日期
select str_to_date('1992-4-3', '%Y-%m-%d') output;
#查询入职日期为1992-4-3的员工信息
select * from employees where hiredate='1992-4-3';
select * from employees where hiredate=str_to_date('4-3-1992', '%m-%d-%Y');
#date-format:将日期转换成字符
select date_format(now(), '%Y年%m月%d日');
#查询有奖金的员工名和入职日期
select last_name, date_format(hiredate, '%m月/%d日 %Y年') 入职日期
from employees
where commission_pct is not null;
其他函数
/*version版本
database当前库
user当前连接用户*/
select version();
select database();
select user();
流程控制函数
/*if 处理双分支
case语句 处理多分支
情况1:处理等值判断
情况2:处理条件判断*/
select if(10 > 5, '大', '小') aa;
select last_name, commission_pct, if(commission_pct is null, '没奖金', '有奖金') aa
from employees;
/*
case的使用法一:
case 要判断的字段或表达式
when 条件1 then 要显示的值1或语句1
when 条件2 then 要显示的值2或语句2
when 条件3 then 要显示的值3或语句3
......
else 要显示的值n或语句n
end 【as 别名】
*/
select salary 原始工资, department_id,
case department_id
when 30 then salary*1.1
when 40 then salary*1.2
when 50 then salary*1.3
else salary
end as 新工资
from employees;
/*
case的使用法二:
case
when 条件1 then 要显示的值1或语句1
when 条件2 then 要显示的值2或语句2
when 条件3 then 要显示的值3或语句3
......
else 要显示的值n或语句n
end 【as 别名】
*/
select salary 原始工资, department_id,
case
when salary>20000 then 'A'
when salary>15000 then 'B'
when salary>10000 then 'C'
else 'D'
end as 工资级别
from employees;
2.2 分组函数
/*sum 求和
max 最大值
min 最小值
avg 平均值
count 计数
特点:
1、以上五个分组函数都忽略null值且不计入总数,
2、sum和avg一般用于处理数值型
max、min、count可以处理任何数据类型
3、都可以搭配distinct使用,用于统计去重后的结果
4、count的参数可以支持:字段、*、常量值,一般放1
count(*),计算行数时null的也会包含进去,效率高,最常用
count(1),计算行数时null的也会包含进去,效率高
count(字段名),得到的结果将是除去值为null和重复数据后的结果,效率低
5、和分组函数一同查询的字段要求是group by后的字段
*/
select sum(salary) from employees;
select max(salary) from employees;
select min(salary) from employees;
select avg(salary) from employees;
select count(salary) from employees;
#组合
select sum(salary), max(salary), round(avg(salary)) from employees;
#查询部门编号为90的员工个数
select count(*) as 个数
from employees
where department_id = 90;
分组查询
/*语法:
select 查询的字段,分组函数
from 表
【where 筛选条件】
group by 分组的字段
【order by 子句】
*/
/*
特点:
1、可以按单个字段分组
2、和分组函数一同查询的字段最好是分组后的字段
3、分组筛选
针对的表 位置 关键字
分组前筛选: 原始表 group by的前面 where
分组后筛选: 分组后的结果集 group by的后面 having
4、可以按多个字段分组,字段之间用逗号隔开
5、可以支持排序
6、having后可以支持别名
*/
#查询每个工种的最高工资
select max(salary), job_id
from employees
group by job_id;
#查询每个位置的部门个数
select count(*), location_id
from departments
group by location_id;
#查询邮箱中包含a字符的,每个部门的平均工资
select avg(salary), department_id, email
from employees
where email like '%a%'
group by department_id;
#查询有奖金的每个领导手下员工的最高工资
select max(salary), manager_id
from employees
where commission_pct is not null
group by manager_id;
#查询哪个部门的员工个数大于2
select count(*), department_id
from employees
group by department_id
having count(*) > 2;
#查询每个工种有奖金的员工的最高工资>12000的工种编号和最高工资
select job_id, max(salary)
from employees
where commission_pct is not null
group by job_id
having max(salary) > 12000;
#查询领导编号大于102的每个领导手下的最低工资>5000的领导编号是哪个,以及其最低工资
select manager_id, min(salary)
from employees
where manager_id > 102
group by manager_id
having min(salary) > 5000;
#按员工姓名的长度分组,查询每一组的员工个数,筛选员工个数>5的有哪些
select length(concat(first_name, last_name)) 长度, count(*)
from employees
group by length(concat(first_name, last_name))
having count(*) > 5;
#查询每个部门,每个工种员工的平均工资
select avg(salary), department_id, job_id
from employees
group by department_id, job_id;
#查询每个部门,每个工种员工的平均工资,平均工资大于10000,并且按平均工资的高低显示出来
select avg(salary), department_id, job_id
from employees
where department_id is not null
group by department_id, job_id
having avg(salary) > 10000
order by avg(salary) desc;
3.多表连接查询
/*
按功能分类:
内连接:
等值连接
非等值连接
自连接
外连接:
左外连接
右外连接
全外连接
交叉连接
*/
3.1 内连接
/* sql99语法
select 查询列表
from 表1 别名
inner join 表2 别名
on 连接条件
分类:
等值
非等值
自连接
*/
等值连接
#等值连接
#查询员工名和对应的部门名
select last_name, department_name
from employees, departments
where employees.`department_id` = departments.`department_id`;
#为表起别名:提高语句的简洁度,区分重名字段(注意:起了别名后不能用原来的表名)
#查询员工名、工种号、工种名
select last_name, e.job_id, job_title
from employees as e, jobs as j
where e.job_id = j.job_id;
#查询有奖金的员工名、部门名
select last_name, department_name, commission_pct
from employees e, departments d
where e.department_id = d.department_id and e.commission_pct is not null;
#查询城市名中第二个字符为o的部门名和城市名
select department_name, city
from departments d, locations l
where d.location_id = l.location_id and city like '_o%';
#查询每个城市的部门个数
select count(*) 个数, city
from departments d, locations l
where d.location_id = l.location_id
group by city;
#查询每个工种的工种名和员工的个数,并且按员工个数降序
select job_title, count(*)
from employees e, jobs j
where e.job_id = j.job_id
group by job_title
order by count(*) desc;
#三表连接 sql99语法
#查询员工名、部门名、所在城市
select last_name, department_name, city
from employees e, departments d, locations l
where e.department_id = d.department_id
and d.location_id = l.location_id;
#查询员工名、部门名
select last_name, department_name
from employees e
inner join departments d
on e.department_id = d.department_id;
#查询名字中包含e的员工名和工种名
select last_name, job_title
from employees e
inner join jobs j
on e.job_id = j.job_id
where e.last_name like '%e%';
#查询部门个数 > 3 的城市名和部门个数
select city, count(*)
from departments d
inner join locations l
on l.location_id = d.location_id
group by city
having count(*) > 3;
#查询员工名、部门名、工种名,并按部门名降序
select last_name, department_name, job_title
from employees e
inner join departments d on d.department_id = e.department_id
inner join jobs j on j.job_id = e.job_id
order by department_name desc;
非等值连接
#查询员工的工资和工资级别
select salary, grade_level
from employees e, job_grades j
where salary between j.lowest_sal and j.highest_sal;
#查询员工的工资级别 sql99语法
select salary, grade_level
from employees e
join job_grades g
on e.salary between g.lowest_sal and g.highest_sal;
#查询每个工资级别的个数>20的个数,并且按工资级别降序 sql99语法
select count(*), grade_level
from employees e
join job_grades g
on e.salary between g.lowest_sal and g.highest_sal
group by grade_level
having count(*) > 20
order by grade_level desc;
自连接
#查询员工名和其对应的上级的名称(查员工名要访问一次表,查领导名要再访问一次同一张表)
select e.employee_id, e.last_name, m.manager_id, m.last_name
from employees e, employees m
where m.manager_id = e.employee_id;
#自连接 sql99语法
#查询员工的名字、上级的名字
select e.last_name, m.last_name
from employees e
join employees m
on e.manager_id = m.employee_id;
3.2 外连接
/*
select 查询列表
from 表1 别名
【inner|left outer|right outer|cross】 表2 别名 on 连接条件2
【inner|left outer|right outer|cross】 表3 别名 on 连接条件3
【where 筛选条件】
【group by 分组】
【having 分组后的筛选条件】
【order by 排序列表】
分类:
内连接:inner
外连接:
左外连接:left 【outer】
右外连接:right 【outer】
全外连接:full 【outer】
交叉连接:cross
*/
/*
应用场景:用于查询一个表中有,另一个表中没有的记录
特点:
1、外连接的查询结果为主表中的所有记录
如果从表中有和它匹配的,则显示匹配的值
如果从表中没有和它匹配的,则显示null
外连接查询结果 = 内连接结果 + 主表中有而从表中没有的记录
2、左外连接,left join左边的是主表
右外连接,right join右边的是主表
3、左外和右外交换两个表的顺序,可以实现同样的效果
4、全外连接 = 内连接的结果 + 表1中有但表2中没有的 + 表2中有但表1中没有的
*/
#引入:查询男朋友不在男神表的女神名
select * from beauty;
select * from boys;
#左外
select b.name, bo.*
from beauty b
left outer join boys bo
on b.boyfriend_id = bo.id
where bo.id is null;
#右外,与上结果同
select b.name, bo.*
from boys bo
right outer join beauty b
on b.boyfriend_id = bo.id
where bo.id is null;
#交叉连接(笛卡尔乘积)
select b.*, bo.*
from beauty b
cross join boys bo;
3.3 子查询
/*
含义:
一条查询语句中又嵌套了另一条完整的select语句,其中被嵌套的select语句,称为子查询或内查询,
在外面的查询语句,称为主查询或外查询
分类:
按子查询出现的位置:
select后面:
仅支持标量子查询
from后面:
支持表子查询
where或having后面:
标量子查询(单行)
列子查询(多行)
行子查询
exists后面(相关子查询)
表子查询
按结果集的行列数不同:
标量子查询(结果集只有一行一列)
列子查询(结果集只有一列多行)
表子查询(结果集一般为多行多列)
*/
where或having后面
/*
一、where或having后面
1、标量子查询(单行子查询)
2、列子查询(多行子查询)
3、行子查询(多行多列)
特点:
1、子查询都放在小括号内
2、子查询可以放在from后面、select后面、where后面、having后面,但一般放在条件的右侧
3、子查询优先于主查询执行,主查询使用了子查询的执行结果
4、子查询根据查询结果的行数不同分为以下两类:
①单行子查询
结果集只有一行
一般搭配单行操作符使用:> < = <> >= <=
非法使用子查询的情况:
a、子查询的结果为一组值
b、子查询的结果为空
② 多行子查询
结果集有多行
一般搭配多行操作符使用:any、all、in、not in
in: 属于子查询结果中的任意一个就行
any和all往往可以用其他查询代替
*/
#1、标量子查询(单行子查询)------------------------------------------------
#①查询Abel的工资
select salary
from employees
where last_name = 'Abel';
#查询员工的信息,满足 salary>①结果
select *
from employees
where salary > (
select salary
from employees
where last_name = 'Abel'
);
#②返回job_id与141号员工相同,salary比143号员工多的员工姓名,job_id和工资
#第一步:①查询141号员工的job_id
select job_id
from employees
where employee_id = 141;
#第二步:②查询143号员工的salary
select salary
from employees
where employee_id = 143;
#第三步:查询员工的姓名,job_id和工资,要求job_id=①并且salary>②
select last_name, job_id, salary
from employees
where job_id=(
select job_id
from employees
where employee_id = 141
) and salary > (
select salary
from employees
where employee_id = 143
);
#查询最低工资大于50号部门最低工资的部门id和其最低工资
select min(salary), department_id
from employees
group by department_id
having min(salary) > (
select min(salary)
from employees
where department_id = 50
);
#2、列子查询(多行子查询)------------------------------------------------
#返回location_id是1400或1700的部门中的所有员工姓名
select last_name
from employees
where department_id in(
select distinct department_id
from departments
where location_id in(1400, 1700)
);
#或
select last_name
from employees
where department_id =any(
select distinct department_id
from departments
where location_id in(1400, 1700)
);
#返回location_id不是1400或1700的部门中的所有员工姓名
select last_name
from employees
where department_id not in(
select distinct department_id
from departments
where location_id in(1400, 1700)
);
#或
select last_name
from employees
where department_id <>all(
select distinct department_id
from departments
where location_id in(1400, 1700)
);
#返回其他部门(意思是除去部门IT_PROG的)中比job_id为'IT_PROG'工种任一工资低的员工的员工号、姓名、job_id以及salary
#一、先查询job_id为'IT_PROG'工种任一工资
select distinct salary
from employees
where job_id = 'IT_PROG';
#二、查询员工号、姓名、job_id以及salary,salary < (一)的任意一个
select last_name, employee_id, job_id, salary
from employees
where salary < any(
select distinct salary
from employees
where job_id = 'IT_PROG'
) and job_id <> 'IT_PROG';
#或
select last_name, employee_id, job_id, salary
from employees
where salary < (
select max(salary)
from employees
where job_id = 'IT_PROG'
) and job_id <> 'IT_PROG';
#返回其他部门(意思是除去部门IT_PROG的)中比job_id为'IT_PROG'工种所有工资低的员工的员工号、姓名、job_id以及salary
select last_name, employee_id, job_id, salary
from employees
where salary < all(
select distinct salary
from employees
where job_id = 'IT_PROG'
) and job_id <> 'IT_PROG';
#或
select last_name, employee_id, job_id, salary
from employees
where salary < (
select min(salary)
from employees
where job_id = 'IT_PROG'
) and job_id <> 'IT_PROG';
#3、行子查询(多行多列)------------------------------------------------
#查询员工编号最小并且工资最高的员工信息
select *
from employees
where (employee_id, salary) = (
select min(employee_id), max(salary)
from employees
)select后面
from后面
#查询每个部门的平均工资的工资等级
#(将子查询结果充当一张表,要求必须其别名)
select ag_dep.*, g.grade_level
from (
select avg(salary) ag, department_id
from employees
group by department_id
) ag_dep
inner join job_grades g
on ag_dep.ag between lowest_sal and highest_sal;
exists后面
#结果为0或1,判断是否存在
select exists(
select employee_id
from employees
where salary=300000
);
#查询有员工的部门名
select department_name
from departments d
where exists(
select *
from employees e
where d.department_id = e.department_id
);
#或
select department_name
from departments d
where d.department_id in(
select department_id
from employees
);
#查询没有女朋友的男神信息
use girls;
select bo.*
from boys bo
where bo.`id` not in(
select boyfriend_id
from beauty
);
#或
select bo.*
from boys bo
where not exists(
select boyfriend_id
from beauty b
where bo.`id`=b.`boyfriend_id`
);
3.4 分页查询
/*语法:
select 字段|表达式,...
from 表
【where 条件】
【group by 分组字段】
【having 条件】
【order by 排序的字段】
limit 【offset起始的条目索引,】 size条目数;
特点:
1.起始条目索引从0开始
2.limit子句放在查询语句的最后
3.公式:select * from 表 limit (page-1)*sizePerPage,sizePerPage
假如:
每页显示条目数sizePerPage
要显示的页数 page
*/
#查询前五条员工信息
select * from employees limit 0, 5;
#查询第11条到第25条
select * from employees limit 10, 15;
#有奖金的员工信息,并且工资较高的前10名显示出来
select *
from employees
where commission_pct is not null
order by salary desc
limit 10;
3.5 联合查询
/*
语法:
select 字段|常量|表达式|函数 【from 表】 【where 条件】 union 【all】
select 字段|常量|表达式|函数 【from 表】 【where 条件】 union 【all】
select 字段|常量|表达式|函数 【from 表】 【where 条件】 union 【all】
.....
select 字段|常量|表达式|函数 【from 表】 【where 条件】
特点:
1、多条查询语句的查询的列数必须是一致的
2、多条查询语句的查询的列的类型和顺序要一致
3、union代表去重,union all代表不去重
*/
#查询部门编号>90或者邮箱包含a的员工信息
select *
from employees where email like '%a%' or department_id > 90;
#等同于
select * from employees where email like '%a%'
union
select * from employees where department_id > 90;
#查询中国用户中男性的信息以及外国用户中年男性的用户信息
select id, cname, csex from t_ca where csex='男'
union
select t_id, tName, tGender from t_ua where tGender = 'male';
4.SQL语言
4.1 增删改
插入
/*
语法:
方式一:(支持插入多行,子查询)
insert into 表名(字段名,...)
values(值1,...), (值1,...), ......;
方式二:(不支持插入多行,不支持子查询)
insert into 表名
set 列名=值, 列名=值, ......;
特点:
1、字段类型和值类型一致或兼容,而且一一对应
2、可以为空的字段,可以不用插入值,或用null填充
3、不可以为空的字段,必须插入值
4、字段个数和值的个数必须一致
5、字段可以省略,但默认所有字段,并且顺序和表中的存储顺序一致
*/
#方式一:多行
insert into beauty(id, name, sex, borndate)
values(13, '唐艺昕', '女', '1990-4-3'), (14, '刘亦菲', '女', '1987-4-3');
#方式一:子查询(会把结果插入对应的字段中)
insert into beauty(id, name, phone)
select 26, '宋茜', '88888888888'
#方式二:
insert into beauty
set id=13, name='唐嫣', sex='女', borndate='1998-9-1';
删除
/*
单表的删除:
delete from 表名 【where 筛选条件】
多表的删除:
delete 别名1,别名2
from 表1 别名1,表2 别名2
where 连接条件
and 筛选条件;
truncate语句:(又称清空,一次删除整个表,不能加where条件)
truncate table 表名
区别:
1.truncate不能加where条件,而delete可以加where条件
2.truncate的效率高一丢丢
3.truncate 删除带自增长的列的表后,如果再插入数据,数据从1开始delete 删除带自增长列的表后,如果再插入数据,数据从上一次的断点处开始
4.truncate删除不能回滚,delete删除可以回滚
*/
#删除手机号以9结尾的女神信息
delete from beauty where phone like '%9';
#删除张无忌女朋友的信息
delete b
from beauty b
inner join boys bo
on b.boyfriend_id = bo.id
where bo.boyName = '张无忌';
#删除黄晓明的信息和他女朋友的信息
delete b, bo
from beauty b
inner join boys bo
on b.boyfriend_id = bo.id
where bo.boyName = '黄晓明';
修改
/*
修改单表语法:
update 表名
set 字段=新值,字段=新值
【where 条件】
修改多表语法:
update 表1 别名1,表2 别名2
set 字段=新值,字段=新值
where 连接条件
and 筛选条件
*/
#修改beauty表中姓唐的女神的电话为88888888888,
update beauty
set phone='88888888888'
where name like '唐%';
#修改张无忌女朋友的手机号为123
update boys bo
inner join beauty b
on bo.id = b.boyfriend_id
where bo.boyName='张无忌';
4.2 库表管理
库的管理
#库的管理
#一、创建库
create database (if not exists) 库名;
#二、删除库
drop database (if exists) 库名;
#三、库的修改
alter database 旧库名 to 新库名;
表的管理
#表的管理
#一、表的创建
create table 表名(
列名 列的类型 【(长度)约束】,
列名 列的类型 【(长度)约束】,
列名 列的类型 【(长度)约束】,
...
);
#例如:
CREATE TABLE IF NOT EXISTS stuinfo(
stuId INT,
stuName VARCHAR(20),
gender CHAR,
bornDate DATETIME
);
#二、表的修改
#1、修改列名
alter table 表名 change 【column】 旧列名 新列名 类型;
#例如:
alter table book change column publishdate pubdate datetime;
#2、修改列的类型或约束
alter table 表名 modify column 列名 类型;
#例如:
alter table book modify column pubdate timestamp;
#3、添加新列
alter table 表名 add column 列名 类型;
#例如:
alter table author add column annual double;
#4、删除列
alter table 表名 drop column 列名 类型;
#例如:
alter table author drop column annual double;
#5、修改表名
alter table 旧表名 rename to 新表名;
#例如:
alter table author rename to zuozhe;
#三、表的删除
drop table 【if exists】 表名;
#四、表的复制
#1、只复制表的结构,不复制数据
create table 新表名 like 被复制表名;
例如:
create table copy_author like author;
#2、复制表的结构 + 全部数据
create table 新表名 select * from 被复制表名;
例如:
create table copy_author select * from author;
#3、复制表的结构 + 部分数据
create table 新表名
select 列名, 列名, ...
from 被复制表名
【where 筛选条件】 ;
#4、只复制部分结构
create table 新表名
select 列名, 列名, ...
from 被复制表名
where 0;
4.3 数据类型
数值类型
1、整数
特点:
a.默认是有符号,无符号需添加unsigned关键字
b.若插入的数值超出范围,会报out of range异常, 并且插入临界值
c.如果不设置长度,会有默认长度,长度代表了显示的最大宽度,如果不够会用0在左边填充,但必须搭配zerofill使用
2、小数
分类:
a.浮点型
float(M, D)
double(M, D)
b.定点型
dec(M, D)
decimal(M, D)
特点:
M:整数部位长度+小数部位长度
D:小数部位长度
注意:M和D都可以省略,如果是decimal,则M默认是10, D默认是0
如果是float和double,则会根据插入的数值精度来决定精度
总结:定点型的精度较高,如果要求插入数值的精度较高如货币运算等可以考虑使用
字符串类型
/*
1、较短的文本(M为字符数)
char(M) 固定长度的字符 空间耗费大,但效率高
varchar(M) 可变长度的字符 空间耗费小,但效率低
2、较长的文本
text
blob
*/
#--------------------------------------------------------------------
enum类型:#又称枚举类型,要求插入的值必须属于列表中指定的值之一
create table tab_char(
c enum('a', 'b', 'c')
);
insert into tab_char values('a');
insert into tab_char values('b');
insert into tab_char values('c');
insert into tab_char values('A');
insert into tab_char values('m'); #报错,因为不包含在枚举列表中
#---------------------------------------------------------------------
set类型 #和enum类型类似,区别在于set类型一次可以选取多个成员,而enum只能选取一个成员
create table tab_set(
s set('a', 'b', 'c', 'd')
);
insert into tab_set values('a');
insert into tab_set values('a, b');
insert into tab_set values('A, b, c');
4.4 常见约束
创建表时添加约束
含义:一种限制,用于限制表中的数据,为了保证表中的数据的准确性和可靠性
创建表时添加约束
/*
常见六大约束:
NOT NULL 保证字段不为空
DEFAULT 保证字段有默认值
UNIQUE 唯一,保证字段值具有唯一性,可以为空
CHECK 检查约束(mysql不支持)
PRIMARY KEY 主键,保证字段值具有唯一性,不能为空
FOREIGN KEY 外键,用于限制两个表的关系,保证该字段的值必须来自于主表的关联列的值,在从表中添加外键约束,用于引用主表中某列的值
*/
#一、添加列级约束----------------------------
/* 语法:
直接在字段名和类型后面追加约束类型即可
只支持:默认、非空、主键、唯一
*/
create table stuinfo(
id int primary key, #主键
stuName varchar(20) not null, #非空
gender char(1) check(gender='男' or gender='女'), #检查
seat int unique, #唯一
age int default, #默认约束
majorId int references(id) #外键
);
#二、添加表级约束----------------------------
/*
语法:在各个字段的最下面
【constraint 约束名】 约束类型(字段名);
*/
create table stuinfo(
id int,
stuname varchar(20),
gender char(1),
seat int,
age int,
majorid int,
constraint pk primary key(id), #主键
constraint uq unique(seat), #唯一键
constraint ck check(gender='男' or gender='女'), #检查
constraint fk_stuinfo_major foreign key(majorid) references major(id) #外键
);
#三、通用写法----------------------------
create table if not exists stuinfo(
id int primary key,
stuName varchar(20) not null,
sex char(1),
seat int unique 18,
age int default,
majorId int,
constraint fk_stuinfo_major foreign key(majorid) references major(id)
);
/*
主键和唯一的对比:
唯一性 是否允许为空 一个表中可以有多少个 是否允许组合
主键 √ × 一个 允许(不推荐)
唯一 √ √ 多个 允许(不推荐)
外键:
1、要求在从表设置外键关系
2、从表的外键列的类型和主表的关联列的类型要求一致或兼容,名称无要求
3、主表的关联列必须是一个key(一般是主键或唯一)
4、插入数据时,先插入主表,再插入从表;删除数据时,先删除从表,再删除主表
*/
修改表时添加约束
/*
1、添加列级约束
alter table 表名 modify column 字段名 字段类型 新约束;
2、添加表级约束
alter table 表名 add 【constraint 约束名】 约束类型(字段名) 【外键的引用】;
*/
alter table stuinfo modify column stuname varchar(20) not null;
alter table stuinfo modify column age int default 18;
alter table stuinfo modify column id int primary key;
alter table stuinfo add primary key(id);
alter table stuinfo modify column seat int unique;
alter table stuinfo add unique(seat);
alter table stuinfo add foreign key(majorid) references major(id);
修改表时删除约束
alter table stuinfo modify column stuname varchar(20) null;
alter table stuinfo modify column age int;
alter table stuinfo drop primary key;
alter table stuinfo drop index seat;
alter table stuinfo drop foreign key fk_stuinfo_major;
标识列
/*
又称自增长列,可以不用手动插入值,系统提供默认的序列值
*/
/*
1、标识列不一定要和主键搭配,但要求是一个key
2、一个表最多可以有一个标识列
3、标识列的类型只能是数值型
4、标识列可以通过 set auto_increment_increment=3; 设置步长,可以手动插入值,设置起始值
*/
#一、创建表时设置标识列
create table tab_identity(
id int primary key auto_increment,
name varchar(20)
);
#会自动创建1-20的id
insert into tab_identity(id, name) values(null, 'john');
#二、修改表时设置标识列
alter table tab_identity modify column id int primary key auto_increment;
#三、修改表时删除标识列
alter table tab_identity modify column id int;
4.5 事务控制
/*
transaction control language:事务控制语言
事务:
一个或一组sql语句组成一个执行单元,这个执行单元要么全部执行,要么全部不执行
*/
/*
事务的特性:
原子性:一个事务不可再分割,要么都执行要么都不执行
一致性:一个事务执行会使数据从一个一致状态切换到另外一个一直状态
隔离性:一个事务的执行不受其他事务的干扰
持久性:一个事务一旦提交,则会永久的改变数据库的数据
事务的创建:
隐式事务:事务没有明显的开启或结束的标记,比如insert、update、delete语句
显示事务:事务具有明显的开启或结束的标记,前提:必须先设置自动提交功能为禁用
set autocommit=0;
步骤1:开启事务
set autommit=0;
start transaction;(可选)
步骤2:编写事务中的sql语句(select、insert、update、delete)
语句1;
语句2;
...
步骤3:结束事务
commit; (提交事务)
rollback; (回滚事务)
*/
set autocommit=0;
start transaction;
update account set balance = 500 where username='张无忌';
update account set balance = 1500 where username='赵敏';
commit;
/*
事务并发问题如何发生?
当多个事务同时操作同一个数据库的相同数据时
事务的并发问题有哪些?
脏读:一个事务读取到了另外一个事务未提交的数据
不可重复读:同一个事务中,多次读取到的数据不一致
幻读:一个事务读取数据时,另一个事务进行更新,导致第一个事务读取到了没有更新的数据
如何避免事务的并发问题?
通过设置事务的隔离级别
1、read uncommitted
2、read committed 可以避免脏读
3、repeatable read 可以避免脏读、不可重复读和一部分幻读
4、serializable 可以避免脏读、不可重复读和幻读
设置隔离级别:
set session|global transaction isolation level 隔离级别名;
查看隔离级别:
select @@tx_isolation;
*/
4.6 视图
#视图
/*
含义:
虚拟表,和普通表一样使用
好处:
1、sql语句提高重用性,效率高
2、和表实现了分离,提高了安全性
视图和表的区别:
使用方式 占用物理空间 语法
视图 完全相同 不占用,仅仅保存的是sql逻辑 create view
表 完全相同 占用 create table
*/
一、视图的创建
#查询姓名中包含a字符的员工名、部门名和工种信息
1、创建
create view myview
as
select last_name, department_name, job_title
from employees e
join departments d on e.department_id = d.department_id
join jobs j on e.job_id = j.job_id;
2、使用
select * from myview where last_name like '%a%';
#查询平均工资最低的部门名和工资
create view myv2
as
select avg(salary) ag
from employees
group by department_id;
create view myv3
as
select * from myv2
order by ag
limit 1;
select d.*, m.ag
from myv3 m
join departments d
on m.department_id = d.department_id;
二、视图的修改
/*
方式一:
create or replace view 视图名
as
查询语句
*/
create or replace view myv3
as
select avg(salary), job_id
from employees
group by job_id;
/*
方式二:
alter view 视图名
as
查询语句
*/
alter view myv3
as
select * from employees;
三、视图的删除
/*
语法:
drop view 视图名, 视图名, ...
*/
drop view myv1, myv2, myv3;
四、视图的查看
/*
语法:
show create view 视图名;
*/
五、视图的更新(更改数据)
1、插入
insert into myv1 values('张飞', 'zf@qq.com');
2、修改
update myv1 set last_name = '张无忌' where last_name = '张飞';
3、删除
delete from myv1 where last_name = '张无忌';
4.7 变量
/*
系统变量:
全局变量:服务器每次启动将为所有的全局变量赋初值,针对于所有的会话有效,但不能 跨重启
会话变量:仅仅针对当前会话有效
自定义变量:
用户变量:针对于当前会话有效,应用在任何地方,即begin end里面或begin end外面
局部变量:仅仅在它的begin end中有效,应用在begin end中的第一句话
*/
一、系统变量
说明:由系统提供,属于服务器层面
1、查询所有的系统变量
show global|【session】 variables;
2、查看满足条件的部分系统变量
show global|【session】 variables like '%char%';
3、查看指定的某个系统变量的值
select @@global|【session】.系统变量名;
4、为某个系统变量赋值
set global|【session】 系统变量名=值;
set @@global|【session】.系统变量名=值;
二、自定义变量
1、说明:用户自定义变量
使用步骤:
声明->赋值->使用
1、声明并初始化
set @用户变量名=值;
或
set@用户变量名:=值;
或
select @用户变量名:=值;
2、赋值(更新用户变量的值)
方式一:
set @用户变量名=值;
或
set@用户变量名:=值;
或
select @用户变量名:=值;
方式二:
select 字段 into 变量名
from 表;
3、使用
select @用户变量名;
例如:
set @name='john';
set @name=100;
set @count=1;
select count(*) into @count
from employees;
select @count;
2、局部变量:
1、声明
declare 变量名 类型;
declare 变量名 类型 default 值;
2、赋值
方式一:通过 set 或 select
set 局部变量名=值;
或
set 局部变量名:=值;
或
select @局部变量名:=值;
方式二:通过 select into
select 字段 into 局部变量名
from 表;
3、使用
select 局部变量名;
例如:
declare m int default 1;
declare n int default 2;
declare sum int;
set sum=m+n;
select sum;
4.8 存储过程和函数
含义:一组预先编译好的SQL语句的集合,理解成批处理语句
1、提高代码的重用性
2、简化过程
3、减少了编译次数并且减少了和数据库服务器的连接次数,提高了效率
一、创建语法
create procedure 存储过程名(参数列表)
begin
存储过程体(一组合法的SQL语句)
end
注意:
1、参数列表包含三部分
参数模式 参数名 参数类型
例如: in stuname varchar(20)
参数模式:
in:该参数可以作为输入,需要调入方传入值
out:该参数可以作为输出,该参数可以作为返回值
inout:该参数既可以作为输入又可以作为输出,也就是该参数既需要传入值,又可以返回值
2、如果存储过程体仅仅只有一句话, begin end 可以省略
存储过程体中的每条SQL语句的结尾要求必须加分号
存储过程的结尾可以使用 delimiter 重新设置
语法:
delimiter 结束标记
例如:
delimiter $
二、调用语法
call 存储过程名(实参列表);
三、参数前面的符号的意思
in:该参数只能作为输入 (该参数不能做返回值)
out:该参数只能作为输出(该参数只能做返回值)
inout:既能做输入又能做输出
5.流程控制
5.1 函数
/*
含义:一组预先编译好的SQL语句的集合,可理解成批处理语句
1、提高代码的重用性
2、简化操作
3、减少了编译次数并且减少了和数据库服务器的连接次数,提高了效率
区别:
存储过程:可以有0个返回,也可以有多个返回,适合做批量插入、批量更新
函数:有且仅有一个返回,适合做处理数据后返回一个结果
*/
/*
一、创建语法
create function 函数名(参数列表) return 返回类型
begin
函数体
end
注意:
1、参数列表包含两部分:
参数名、参数类型
2、函数体:肯定会有return语句,如果没有会报错,如果return语句没有放在函数体的最后不会报错,但不建议return 值
3、函数体中仅有一句话,则可以省略begin end
4、使用 delimiter 语句设置结束标记
二、调用语法
select 函数名(参数列表)
三、查看函数
show create function 函数名;
四、删除函数
drop function 函数名;
*/
#返回公司的员工个数(无参返回)
create function myf1() returns int
begin
declare c int default 0 #定义变量
select count(*) into c #赋值
from employees;
return c;
end $
#根据员工名返回他的工资(有参返回)
create function myf2(cmpName varchar(20)) return double
begin
set @sal=0;
select salary into @sal
from employees
where last_name = empName;
return @sal;
end $
5.2 流程控制图
/*
顺序结构:程序从上往下依次执行
分支结构:程序从两条或多条路径中选择一条去执行
循环结构:程序在满足一定条件的基础上,重复执行一段代码
*/
一、分支结构
1、 if 函数
语法:if(条件,值1,值2)
特点:可以用在任何位置
2、 case 结构
情况一:类似于switch
case 表达式
when 值1 then 结果1或语句1(如果是语句,需要加分号)
when 值2 then 结果2或语句2(如果是语句,需要加分号)
...
else 结果n或语句n(如果是语句,需要加分号)
end 【case】(如果是放在begin end中需要加上case,如果放在select后面不需要)
情况二:类似于多重if
case
when 条件1 then 结果1或语句1(如果是语句,需要加分号)
when 条件2 then 结果2或语句2(如果是语句,需要加分号)
...
else 结果n或语句n(如果是语句,需要加分号)
end 【case】(如果是放在begin end中需要加上case,如果放在select后面不需要)
3、 if 结构
if 情况1 then 语句1;
elseif 情况2 then 语句2;
...
else 语句n;
end if;
二、循环结构
语法:
【标签:】WHILE 循环条件 DO
循环体
END WHILE 【标签】;
特点:
只能放在BEGIN END里面
如果要搭配leave跳转语句,需要使用标签,否则可以不用标签
leave类似于java中的break语句,跳出所在循环!!!
...