目录
数据库(database):存储管理数据的仓库
数据库管理系统(database management system):操作和管理数据库的大型软件
SQL(structured query language):操作关系型数据库的编程语言,定义了一套操作关系型数据库的统一标准
前提:配置好mysql的环境变量
进入计算机命令行界面:mysql -u用户名 -p密码
注意:密码也可以不输直接回车,但是回车后还需输入密码
含义:建立在关系模型基础上,由多张相互连接的二维表组成的数据库
理解:我们安装了mysql之后我们的计算机就成为了mysql数据库服务器,我们就可以通过mysql客户端来连接mysql数据库管理系统DBMS,就可以使用sql语句通过数据库管理系统来创建数据库,也可以通过sql语句通过DBMS在指定的数据库当中创建表以及实现增删改查,在一个数据库服务器当中是可以创建多个数据库的,在一个数据库中可以创建多个表的
注意:表中的字段为表的列名
注释分类 | 注释符号 |
单行注释 | #注释内容或者--注释内容 |
多行注释 | /*注释内容*/ |
注意:
关于char和varchar
注意:日期和时间类型在写sql语句的时候应该由引号包裹
DDL为数据库定义语言,用于定义数据库以及表
查询所有数据库:show databases;
查询当前数据库:select database();
创建数据库:create database [if not exists] 数据库名 [default charset utf8mb4];
删除数据库:drop database [if exists] 数据库名;
使用数据库:use 数据库名;
注意:
查询当前数据库所有的表:show tables;
查询表结构:desc 表名;
查询指定表的建表语句:show create table 表名;
创建表:create table 表名(字段名 字段类型(字段长度),字段名 字段类型(字段长度));
添加表字段:alter table 表名 add 字段名 字段类型(字段长度) [约束];
修改表中指定字段的数据类型:alter table 表名 modify 字段名 新数据类型(长度);
修改表中的字段名以及字段类型:alter table 表名 change 旧字段名 新字段名 类型(字段长度) [约束];
删除字段:alter table 表名 drop 字段名;
修改表名:alter table 表名 rename to 新表名;
直接删除表:drop table [if exists] 表名;
删除指定表并创建同名新表:truncate table 表名;(注意:新表没数据)
注意:表操作必须得先通过use指令使用具体数据库
DML为数据库操纵语言,用来对数据库中表的数据进行增删改操作
给指定字段添加数据:insert into 表名(字段名1,字段名2)values(字段值1,字段值2);
给指定字段批量添加数据:insert into 表名(字段名1,字段名2)values(字段值1,字段值2),(字段值1,字段值2),(字段值1,字段值2);
给全部字段添加数据:insert into 表名 values(值1,值2,……);
给全部字段批量添加数据:insert into 表名 values(值1,值2,……),(值1,值2,……),(值1,值2,……);
修改表中数据:update 表名 set 字段名1=值1,字段名2=值2,…… [where条件];
删除表中数据:delete from 表名 [where条件];
注意:
数据库查询语言,用来查询数据库表中的记录关键字select
首先from查表,查表之后进行where过滤,过滤之后对其进行group by分组,分组之后再having过滤,过滤之后对其进行select查询,查询之后进行order by排序,排序完直接limit分页
数据控制语言,用来管理数据库用户,控制数据库的访问权限
理解:DCL主要控制的是有那些用户可以来访问我们这台mysql服务器,当itcard这个用户来访问我们这个mysql服务器的时候,他能够操作哪几个数据库
查询用户:select * from user
注意:(只有查询用户的前提是进入mysql数据库:use mysql)
创建用户:create user ‘用户名’@‘主机名’ identified by '密码’;
修改用户密码:set password for '用户名'@'主机名'=password('新密码');
删除用户:drop user ‘用户名’@‘主机名’;
- #创建用户名idcard,只能在当前主机访问,密码为123456
- create user 'idcard'@'localhost' identified by '123456';
-
- #创建用户名baima,可以在任意主机上访问数据库,密码为12306
- create user 'baima'@'%' identified by '12306';
-
- #修改idcard用户密码为666(
- set password for 'idcard'@'localhost'=password('666');
-
- #删除用户baima
- drop user 'baima'@'%';
注意:
mysql中定义了很多权限,常用的有以下几种
查询权限
语法:show grants for ‘用户名’@‘主机名’;
授予权限
语法:grant 权限列表 on 数据库名.表名 to ’用户名‘@’主机名‘;
撤销权限
语法:revoke 权限列表 on 数据库名.表名 from ’用户名‘@’主机名‘;
- #查看idcard用户的权限
- show grants for 'idcard'@'localhost';
-
- #授予idcard所有权限
- grant all on mysql.user to 'idcard'@'localhost';
-
- #撤销idcard的所有权限
- revoke all on mysql.user from 'idcard'@'localhost';
注意:
注意:
- select e.ename,e.job from emp e;
- #因为先查表,查表后as起别名已经生效了
语法:select 字段列表 from 表名 where 条件列表;
注意:+,-,*,/等这些算数运算符也可以用在查询里面
- #查询emp=400员工的job
- select job from emp where empno=400;
-
- #查询薪资小于等于3500员工的姓名
- select ename from emp where sal<=3500;
-
- #查询job=员工并且薪资=3000的人的所有信息
- select * from emp where job="员工" and sal=3000;
-
- #查询job为员工或者sal为3500的人的所有信息
- select * from emp where job="员工" or sal=3500;
-
- #查询mgr为null的人的ename以及job
- select ename,job from emp where mgr is null;
-
- #查询mgr不为null的人的ename以及job
- select ename,job from emp where mgr is not null;
-
- #查询薪资在3200和80000之间的人的所有信息
- select * from emp where sal between 3200 and 80000;
- #注意:在这里范围包括3200以及80000,并且and前面接的数一定要小于and后面接的数
-
- #查询薪资不在3200和80000之间的人的所有信息
- select * from emp where sal not between 3200 and 80000;
-
- #查询sal的薪水在in的集合中人的所有信息
- select * from emp where sal in(3500,90000);
-
- #查询sal的薪水不在in的集合中人的所有信息
- select * from emp where sal not in(3500,90000);
-
- #查询ename以l开头并且后面有2个字符的人的信息
- select * from emp where ename like "l__";
-
- #查询ename不以l开头或者以l开头但后面没有确定2个字符的人的信息
- select * from emp where ename not like "l__";
-
- #查询ename第二个字符为a并且一共有4个字符的人的所有信息
- select * from emp where ename like "_a__";
-
- #查询ename中以h开头的人的所有信息
- select * from emp where ename like "h%";
-
- #查询ename中间包含e的人的所有信息
- select * from emp where ename like "%e%";
-
- #查询ename中以m结尾的人的所有信息
- select * from emp where ename like "%m";
-
- #查询出ename与员工sal和comm的总和
- select ename,sal+comm from emp;
-
- ##查询出ename与员工sal除comm的值并向上取整
- select ename,ceil(sal/comm) from emp;
注意:如果语义都不清楚则加括号
含义:将一列数据作为一个整体进行纵向计算
语法:select 聚合函数(字段) from 表名;
- #查询该表的总体行数
- select count(*) from emp;
- select count(1) from emp;
-
- #查询mgr字段的有数据量的总体行数
- select count(mgr) from emp;
-
- #查询sal字段的最大值
- select max(sal) from emp;
-
- #查询sal字段的最小值
- select min(sal) from emp;
-
- #查询sal的平均值
- select avg(sal) from emp;
-
- #求sal字段的总和
- select sum(sal) from emp;
注意:null值是不参与聚合函数的计算的
语法:select 字段列表 from 表名 [where 条件] group by 分组字段列表 [having 分组过滤条件];
执行时机不同:where是分组之前进行过滤,不满足where条件不参与分组;而having是分组之后对结果进行过滤
判断条件不同:where不能对聚合函数进行判断,而having可以
- #根据性别分组,统计男女员工数量
- select sex,count(1) from emp group by sex;
-
- #根据性别分组,统计男女员工的平均薪资
- select sex,avg(sal) from emp group by sex;
-
- #查询薪资小于20000的员工,根据性别分组,查出最大工资大于3600的组的数据
- select count(*) from emp where sal<20000 group by sex having max(sal)>3600;
表用例inoutinfo
- #先以number进行分组分成了粤BS8120和粤BS8121,再在此情况下将粤BS8120和粤BS8121这两组打开以status进行精分
- #查询在不同状态下每种车辆的用费情况
- select number,status,sum(spend) from inoutinfo group by number,status;
语法:select 字段列表 from 表名 order by 字段1 排序方式,字段2 排序方式;
理解:现以字段1进行排序,如果字段1相同则以字段2进行排序
- #按照薪资进行升序排序
- select * from emp order by sal asc;
-
- #按照薪资进行升序排序再按照mgr降序排序
- select * from emp order by sal asc,mgr desc;
语法:select 字段列表 from 表名 limit 略过信息条数,查询记录数;
注意:
- select 字段列表 from 表名 limit m,n;
- #一共5页每页10条数据,我要从第8页的第三行开始取3条数据,要略过7*10+2条数据
- #m=7*10+2
- #n=3
- #查询3条数据
- select * from emp limit 3;
- select * from emp limit 0,3;
-
- #略过2条数据,查询2条数据
- select * from emp limit 2,2;
含义:函数指一段可以直接被另一段程序调用的程序和代码
注意:mysql中本身内置了很多的函数,我们要做的就是要调用这些函数来完成我们的业务需求
length(str):获取字符串的长度
replace(str,'s1','s2'):将str内的s1字符串换为s2字符串
locate(str1,str2):判断str2是否包含str1,如果包含则返回str1在str2内的位置(从1开始),不包含则返回0
- #将empno的所有数据并前面都加0后面都加1来显示
- select concat('0',empno,'1') from emp;
-
- #将HELLO全部转为小写显示
- select lower("HELLO");
-
- #将ename里的数据全部用大写的方式显示
- select upper(ename) from emp;
-
- #将hello用6向左填充达到9个字符来显示
- select lpad('hello',9,'6');
-
- #去掉“ hello world ”两端的空格
- select trim(" hello world ");
-
- #截取hiredate内的月份——从第6个开始截取,截取两个
- select substring(hiredate,6,2) from emp;
-
- #求处hello的长度
- select length("hello");
-
- #将hello里的e换成o
- select replace("hello","e","o");
-
- #判断hello world是否包含wo
- select locate("wo","hello world");
uuid():生成一个32位的随机数
- #对1.1进行向上取整
- select ceil(1.1);
-
- #对3和4进行求模运算(3/4后取余)
- select mod(3,4);
-
- #求0-1之间的随机数
- select rand();
-
- #对3.1415926进行4舍5入,保留3位小数
- select round(3.1415926,3);
-
- #生成一个32位的随机数
- select uuid();
hour(date):获取当前date的小时
minute(date):获取当前时间的分钟
second(date):获取当前时间的秒数
定义日期/时间格式:
- date_format(time,自定义时间格式)或者:time_format(time,自定义时间格式)
- date_format(date,自定义日期格式)
- date_format(datetime,自定义日期时间格式)
关于日期/时间格式转换函数
- #显示当前日期-(年-月-日)
- select curdate();
-
- #显示当前时间-(时:分:秒)
- select curtime();
-
- #显示当前日期和时间-(年-月-日 时:分:秒)
- select now();
-
- #显示年月日时分秒
- select year(now()),month(now()),day(now()),hour(now()),minute(now()),second(now());
-
- #求当前时间往后推70天的时间
- select date_add(now(),interval 70 day);
-
- #求2021年12月1号到现在相差的天数
- select datediff(now(),'2021-12-01');
-
- #将现在时间的时分秒转化为以横杠相连接的格式——其实格式可以自定义
- select time_format(now(),"%H-%i-%s");
-
- #将现在的日期转化为以:相连的格式
- select date_format(now(),"%Y:%m:%d");
-
- #将现在的日期时间转化为自定义格式
- select date_format(now(),"%Y:%m:%d %H-%i-%s");
流程控制函数也是常用的一类函数,可以在sql语句中实现条件筛选,从而提高语句的效率
- #如果值为true返回ok,否则返回error
- select if(false,"ok","error");
-
- #如果值不为空则返回该值,如果为空,返回第二个
- select ifnull(null,"value2");
- #注意:null不能用单引号引起来
-
- #查询ename和sal,如果sal>3500则显示高,否则低
- select ename,
- case when sal>3500 then "高" else "低" end
- from emp;
-
- #查询job为员工则显示true否则显示false
- select ename,
- case job when "员工" then "true" else "false" end
- from emp;
- #注意:else可以被when替代继续执行多分支
含义:作用于表中字段的规则,用于限制存储在表中的数据
目的:保证数据库中数据的正确性,有效性和完整性
- create table user (
- id int primary key auto_increment comment '主键',
- name varchar(10) not null unique comment '非空唯一',
- age int check(age>0 && age<=120),
- status char(1) default '1' comment '默认',
- gender char(1) comment '无约束'
- ) comment '用户表';
注意:
含义:用来让两张表之间建立连接,从而保证数据的一致性和完整性
添加外键语法:
alter table 表名 add constraint 外键名称 foreign key(当前表外键) references 主表(主表主键);
create table 表名(
字段名 字段类型(字段长度),
……
[constraint] [外键名称] foreign key(当前表外键) references 主表(主表主键)
);
删除外键语法:alert table 表名 drop foreign key 外键名称;
- #为emp添加外键以dept为主表
- alter table emp add constraint fk_emp_dept_id foreign key(dept_id) references dept(id);
-
- #删除名字为fk_emp_dept_id的外键
- alter table emp drop foreign key fk_emp_dept_id;
- #为emp添加外键并指定外键的更新行为cascade删除行为cascade
- alter table emp add constraint fk_emp_dept_id foreign key(dept_id) references dept(id) on update cascade on delete cascade;
注意:
在项目开发中,在进行数据库表结构设计时,会根据业务需求及业务模块之间的联系,分析并设计表结构,由于业务之间相互关联,所以各个表结构之间也存在着各种联系,基本上分为3种
多表查询:指从多张表中查询数据
笛卡尔积:也称叉乘或交叉连接,是指在数学中,两个集合A集合和B集合的所有组合情况。
语法:select 字段列表 from 表1,表2;
找两个或多个表之间的关联关系如表一的dept_id和表2的id相关联那么就可以写成
select 字段列表 from 表1,表2 where 表1.dept_id=表2.id;
内连接:相当于查询a与b交集的部分
外连接
- 左外连接:查询左表的所有数据,以及两张表交集部分的数据
- 右外连接:查询右表的所有数据,以及两张表交集部分的数据
自连接:当前表与自身表的连接查询,自连接必须使用表别名
隐式内连接语法:select 字段列表 from 表1,表2 where 条件……;
显式内连接语法:select 字段列表 from 表1 [inner] join 表2 on 连接条件 ……;
- #查询每一个员工的姓名以及关联部门的名称
- select emp.name,dept.name from emp,dept where dept.id=emp.dept_id;
- select emp.name,dept.name from emp inner join dept on dept.id=emp.dept_id;
左外连接语法:select 字段列表 from 表1 left [outer] join 表2 on 条件……;
右外连接语法:select 字段列表 from 表1 right [outer] join 表2 on 条件……;
- #查询emp表的所有数据以及对应的部门信息
- select * from emp left outer join dept on dept.id=emp.dept_id;
-
- #查询dept表的所有数据以及对应的员工信息
- select * from emp right outer join dept on dept.id=emp.dept_id;
注意:join on之后的数据也可以作为一个结果集继续join on进而实现多表查询
自连接语法:select 字段列表 from 表A 别名A join 表A 别名B on 条件……;
注意:自连接的查询可以是内连接查询,也可以是外连接查询
- #查询员工及其所属领导的名字(managerid对应id)
- select a.name,b.name from emp a,emp b where a.managerid=b.id;
- select a.name,b.name from emp a join emp b on a.managerid=b.id;
-
- #查询所有员工以及领导的名字,如果员工没有领导,则也需要查询出来
- select a.name,b.name from emp a left join emp b on a.managerid=b.id;
对于联合查询,就是把多次查询的结果合并起来,形成一个新的查询结果集
语法:
select 字段列表 from 表A……
union [all]
select 字段列表 from 表B……
- #将薪资低于11000的员工和年龄大于40的员工全部查询出来
- select * from emp where salary <11000
- union all
- select * from emp where age>40;
-
- #将薪资低于11000的员工和年龄大于40的员工全部查询出来并去重
- select * from emp where salary <11000
- union
- select * from emp where age>40;
注意:
含义:sql语句中嵌套select语句,成为嵌套查询,又称子查询(就是小括号里面的查询)。
语法:select * from 表1 where 特定字段=(select 特定字段 from 表2);
注意:
子查询返回的结果为单个值(数字、字符串、日期等),最简单的形式,这种子查询称为表领子查询
常用的操作符:=、<>、>、>=、<、<=
- #查询研发部的所有员工信息(查询结果为单个值用=号)
- select * from emp where dept_id=(select id from dept where name="研发部");
-
- #查询查询小昭入职日期之后的员工信息
- select * from emp where entrydate>(select entrydate from emp where name="小昭");
含义:子查询返回的结果是一列
常用的操作符:in、not in、any、some、all
- #查询销售部和市场部的所有员工信息
- select * from emp where emp.dept_id in(select id from dept where name in("市场部","财务部"));
-
- #查询比财务部所有人工资都高的员工信息
- -- 查询所有财务部的人员工资
- select salary from emp where dept_id=(select id from dept where name="财务部");
- -- 查询比财务部所有人工资都高的员工信息(因为要比较多个,所以用all关键字)
- select * from emp where salary >all(select salary from emp where dept_id=(select id from dept where name="财务部"));
-
- #查询比研发部任意一人工资高的员工信息(就是比研发部最低工资人的工资高就可以)
- select * from emp where salary >some(select salary from emp where dept_id=(select id from dept where name="研发部"));
含义:子查询的返回结果是一行
常用的操作符:=、<>、in、not in
- #查询与张无忌的薪资及直属领导相同的员工信息
- -- 查询张无忌的薪资及直属领导
- select salary,managerid from emp where name="张无忌";
- -- 查询与张无忌薪资及直属领导相同的员工信息
- select * from emp where (salary,managerid)=(12500,1);#迭代
- select * from emp where (salary,managerid)=(select salary,managerid from emp where name="张无忌");
含义:子查询的返回结果为多行多列
常用操作符:in
- #查询和韦一笑或张无忌的职位和薪资相同的员工信息
- -- 查询韦一笑,张无忌的职位和薪资
- select job,salary from emp where name in("韦一笑","张无忌");
- -- 查询与韦一笑或张无忌相同职位和薪资的员工信息
- select * from emp where (job,salary) in(select job,salary from emp where name in("韦一笑","张无忌"));
-
- #查询入职日期是2004-01-01之后的员工信息及部门信息
- -- 查询入职日期是2004-01-01之后的员工信息
- select * from emp where entrydate>"2004-01-01";
- -- 查询这部分员工对应的部门信息
- select e.*,d.* from (select * from emp where entrydate>"2004-01-01") e left join dept d on e.dept_id=d.id;
含义:是一组操作的集合,它是一个不可分割的工作单位,事务会把所有的操作作为一个整体一起向系统提交或撤销操作请求,即这些操作要么同时成功,要么同时失败
注意:对于mysql数据库来说,事务是自动提交的,也就是说,当执行一条DML语句,mysql会立即隐式的提交事务
查看事务的提交方式:select @@autocommit;
设置事务的提交方式:set @@autocommit=提交值(0/1)
注意:如果提交值为1那么事务就是自动提交,如果值为0,那么就是手动提交
提交事务:commit;
回滚事务:rollback;
注意:回滚事务就是回滚到事务的起点
- #查看事务的提交方式
- select @@autocommit;
- #设置提交方式为手动提交
- set @@autocommit=0;
- #转账操作
- -- 1查询张三账户余额
- select * from account where name='张三';
- -- 将张三账户余额-1000
- update account set money=money-1000 where name='张三';
- -- 将李四账户余额+1000
- update account set money=money+1000 where name='李四';
- #提交事务
- commit;
- set @@autocommit=1;
开启事务:start transaction;或者begin;
提交事务:commit;
回滚事务:rollback;
- #开启事务
- begin;
- #转账操作
- -- 1查询张三账户余额
- select * from account where name='张三';
- -- 将张三账户余额-1000
- update account set money=money-1000 where name='张三';
- -- 将李四账户余额+1000
- update account set money=money+1000 where name='李四';
- #回滚事务
- rollback;
- #用此方式那么下以上转账会打包在一起执行,中间任何一个过程出错则不会提交
脏读:一个事务读取到另一个事务未提交的数据,另一个事务回滚了,则此事务得到的数据是无效数据也称脏数据。
不可重复读:一个事务对于同一个数据多次查询,另一个事务在该事务查询期间对此事物数据进行修改,则第一个事务会得到两种不同的结果
幻读:一个事务对此数据进行批量操作(删除/插入)另一个事务对此数据进行(插入/删除),则会得到意想不到的效果
查看当前会话隔离级别:select @@tx_isolation;
查看系统当前隔离级别:select @@global.tx_isolation;
设置事务的隔离级别:
set session|global transaction isolation level read uncommitted|read committed|repeatable read|serializable;
注意:session表示仅针对当前客户端窗口有效,global表示针对于所有客户端窗口有效
理解:
下面的列名为例
地址——(可分)——>省、市、详细地址。
此时就把地址这一列分为3列;分别为省、市、详细地址
其要求数据库表中的每个实例或行必须可以被唯一的区分,为实现区分,通常需要为表加上一个列,以储存各个实例的唯一标识,这个唯一属性的列被称为主键。(有主键)
注意:数据不存在传递关系,即每个属性都和主键直接相关而不是间接相关
理解:
现在有4个字段:学号(主键)、所在院校、院校地址、院校电话
有关系
- (学号)<——(所在院校)
- (所在院校)<——(院校地址、院校电话)
由此观之,院校地址、院校电话与主键间接相关,因此我们可以拆分两表
- 一表:学号(主键)、所在院校
- 二表:所在院校(主键)、院校地址、院校电话