1.SQL通用语法
- SQL单行、多行书写,以分号结尾
- SQL可以以空格有缩进增加代码可读性
- SQL语句不区分大小写
2.SQL语句分类
2.1 DDL(数据定义语言)
用于数据库、数据表、字段的定义的语言
create by 表名 (表里有什么字段);
sql
create table employee
(
name varchar(10) comment '姓名',
age tinyint unsigned comment '年龄',
idcard char(10) comment '身份证',
tel char(11) comment '手机号'
);
# name、age、idcard、tel为表里面的字段,
varchar()、char等即数据以什么类型存储进表
comment后面接注释
2.2 DML(数据管理语言)
对表格内容进行增、删、改操作所用到的语言
增
INSERT INTO 表名 (字段) VALUE (值);
字段可省略不写
sql
insert into employee (id, age, sex, address) value (1, 1, '男', '南京');
INSERT INTO 表名 VALUE (值);
sql
insert into employee value (4, 4, '女', '深圳');
批量添加数据 INSERT INTO 表名 (值), (值);
sql
insert into employee value (5, 5, '男', '桂林'), (6, 6, '男', '长沙');
改
UPDATE 表名 SET 字段名1 = 值, 字段名2 = 值, [WHERE 条件]; 如果没有添加条件即把整个表的内容修改
sql
update employee set id = 6 where id <= 6;
将表格中符合id <= 6的数据id改为6
删
DELETE FROM 表名 (条件); DELETE * FROM 表名 若不添加条件即把整个表的数据进行删除
sql
delete from employee where sex = '女';
将表内条件sex为女的数据删除
delete from employee;
将表格内所有数据删除
2.3 DQL(数据查询语言)
基础查询
SELECT 字段1, 字段2 FROM 表名; SELECT FROM 表名; 若不添加字段即查询整个表
sql
#查询数据
#基础查询
# SELECT 字段1, 字段2 FROM 表名;
#1.查询指定字段内容并返回
select name, age
from employee;
# SELECT 字段1 AS 别名1, 字段2 AS 别名2 FROM 表名;
#2.查询指定字段内容,起别名后返回
select name as '姓名', age as '年龄', idcard as '身份证'
from employee;
#两种写法效果一样,as可以省略
select name '姓名', age '年龄', idcard '身份证'
from employee;
# SELECT * FROM 表名; 此时即查询整个表(不建议这么写)
# 建议将所有要查询的字段通通写入,可读性高
#3.查询整个表并返回
select *
from employee;
#4.去除表中重复数据后返回
# 关键字distinct可以去除重复数据
select distinct name '姓名'
from employee;
select distinct age '姓名'
from employee;
条件查询
sql
#1.查询年龄为18的
select age '年龄'
from employee
where age = 18;
#2.查询身份证为空的个人信息
insert into employee value ('张飞', 18, null, '10086'),
('关鱼', 19, null, '10087'),
('刘备', 20, '100403', '1093343');
select *
from employee
where idcard is null;
#3.查询18和19岁的所有人物,用or和in实现
#用or实现
select *
from employee
where age = 18
or age = 19;
#为了简化这繁琐的语法,推出in
select *
from employee
where age in (18, 19, 20);
#4.查询大于18小于21的人物
select *
from employee
where age > 18
and age < 20;
#5.查询在某个范围内的数据
# between and关键字
select *
from employee
where age between 18 and 19;
#6.模糊匹配
select *
from employee
where name like '__';
insert into employee value ('牛比', 66, '10000x', 'null');
# %可以匹配任意字符
select *
from employee
where idcard like '%x';
分组查询
select 字段 from 表名 where (过滤条件) group by 分组字段名 having 分组过滤条件
where和having执行时机不同,where是在分组前对数据进行过滤,having是对分组后的数据进行过滤 where后不能接聚合函数,而having可以
sql
-- 1.查询男女性员工数量
select age, name from employee;
select sex, count(*) from employee group by sex;
-- 2.根据性别分组,统计男女员工平均年龄
select sex, avg(age) from employee group by sex;
-- 3.查询年龄小于43的员工,并根据工作地址分组,获取员工数量大于3的工作地址
select address, count(*) '数量' from employee where age < 43 group by address;
select address, count(address) '数量' from employee where age > 43 group by address having 数量 >= 3 ;
排序查询
select 字段 from 表 order by 排序的内容 asc升序 desc降序 默认升序排序
sql
select * from employee order by age asc ;
分页查询
select 字段 from 表 limit 起始索引, 查询数量
sql
/*查询数量为第一页时,起始地址可以省略
起始索引从0开始,查询页数可以是(页数-1 * 数量),查询数量
分页查询是数据库的方言,sql的分页查询数limit*/
select * from employee limit 0, 5 ;
select * from employee order by age asc limit 0 ,5;
select * from employee order by age desc limit 10, 10;
查询顺序
-- 编写顺序 -- 从哪个表里面查询条件为什么的数据 select 字段列表 from 表格列表 where 条件列表 group by 分组字段列表 having 分组后条件列表 order by 排序字段顺序 limit 分页参数 -- 访问顺序 从哪个表格里,查询条件为,什么的数据进行分组,分组后进行条件过滤,过滤后展示字段列表和分组后的条件列表,将该列表进行排序,最后展示符合条件的数据 真实访问顺序:1. from 2. where 3. group by 4. having 5. select 6. order by 7. limit
2.4 DCL(权限控制语言)
3. 函数
3.1 字符串函数
sql
-- CONCAT(s1, s2, ...) 字符串拼接函数
select concat('hello', ' mysql');
-- lower(str) 将字符串所有字母转换为小写
select lower('HeLLo');
-- upper(str) 将字符串所有字母转换为大写
select upper('HeLLo');
-- lpad(str, n, padstr) 字符串左填充函数:str字符串内容,n填充后总长度,padstr填充内容
select lpad('niubi', 10, '-0');
-- rpad(str, n, padstr) 字符串右填充函数:str字符串内容,n填充后总长度,padstr填充内容
select rpad('niubi', 10, '-');
-- trim(str) 去除头尾部空格
select TRIM(' hello world ');
-- substr(str, start,len) 字符串截取函数:截取的主串,截取的起始位置,截取的长度
select substr('hello world', 1, 7);
-- 练习1.企业员工工号统一为五位数,不足五位数的统一在前面补0
update employee set name = lpad(name, 10, '0');
update employee set name = rpad(name, 10, ' ');
3.2 数值函数
java
-- ceil(x) 向上取整函数
select ceil(1.01);
-- floor(x) 向下取整函数
select floor(1.01);
-- mod(x, y) 取模函数,x % y
select mod(2, 3);
-- rand() 随机数函数,随机返回一个0-1之间的随机数
select rand();
-- round(x) 四舍五入函数
select round(2.33);
select round(2.56);
-- 练习:通过数据库函数,随机生成6位数的验证码
select substr(rand() * 1000000, 1, 6);
3.3 日期函数
sql
-- curdate() 返回当前年月日
select curdate();
-- curtime() 返回当前时分秒
select curtime();
-- now() 返回当前年月日时分秒
select now();
-- year() 获取指定日期的年份
select year(now());
-- month() 获取指定日期的月份
select month(now());
-- day() 获取指定日期的的日期号
select day(now());
-- date_add(日期, interval 增加的日期):函数最终返回增加后的日期
select date_add(now(), interval 20 day);
select date_add(now(), interval 20 year);
select date_add(now(), interval 20 month );
-- datediff(date1, date2) 两个日期间隔天数
select datediff('2028-3-7', '2025-3-7');
3.4 流程函数
sql
-- if(true/false, 值1, 值2):为真则为值1,假则为值2
select if(false, 1, 'error');
-- ifnull(值1, 值2):值1为空则返回值2,否则反之
select ifnull(null, 2);
-- case 查询内容 when 内容是否等于该值 then 返回值1 else 返回默认值 and
-- when then 可以有多个,一个then对应一个when,从when开始依次向后匹配,匹配则返回当前when对应的then,否之返回默认值
-- case when 查询内容是否满足条件,满足返回对应的then,所有when都不匹配则返回默认值
select name,
(case address when '深圳' then '一线城市' when '广州' then '一线城市' else '二线城市' end) '工作地址'
from employee;
select name,
(case when age < 21 then '后生仔' when age = 21 then '半后生仔' else '老年仔' end) '状态'
from employee;
4. 约束
sql
create table user (
id int primary key auto_increment comment '工号',
name varchar(10) unique not null comment '姓名',
age int check ( age > 0 and age < 120 ) comment '年龄',
stauts char(1) default '1' comment '状态',
gender char(1) comment '性别',
dept_id int comment '所属部门'
) comment '用户表';
外键约束的增删改
sql
-- 添加外键约束
-- alter table 表名(子表) add constraint 外键名称 foreign key (添加到该子表的哪个字段) references 父表的(哪个字段)
-- 改变user表 添加外键约束名为fm_emp_dept_id 该约束添加到user中的dept_id字段,该约束来自父表dept的id字段
alter table user add constraint fm_emp_dept_id foreign key (dept_id) references dept(id) ;
-- 删除外键
-- 删除user表名为fm_emp_dept_id字段
alter table user drop foreign key fm_emp_dept_id;
sql
-- 在删除父表的内容时,若该内容与子表有关联,即是子表的外键时,默认采取中止删除/更新的操作
-- 即默认采取 no action 或者 restrict
-- no action 在删除/更新父表内容时,首先检查子表是否与改内容关联,如果有则不允许删除/更新操作
-- restrict 在删除/更新父表内容时,首先检查子表是否与改内容关联,如果有则不允许删除/更新操作
-- cascade 在删除/更新父表内容时,首先检查子表是否与该内容有关联,如果有则一并删除
-- set null 在删除/更新父表内容时,首先检查子表是否与该内容关联,如果有则将子表的该键置空
alter table user add constraint fm foreign key (dept_id) references dept(id) on delete cascade on update cascade ;
alter table user drop foreign key fm;
alter table user add constraint fm foreign key (dept_id) references dept(id) on delete set null on update set null;
5. 多表查询
-- 多表查询的四种方式 -- 方式一:内连接 -- 内连接分为:隐式内连接、显示内连接 -- 方式二:外连接 -- 外连接分为:左外连接、右外连接 -- 方式三:自查询 -- 方式四:子查询
案例演示所用到的两张表
sql
-- 新建员工表
create table emp
(
id int unique primary key comment '工号',
name varchar(10) comment '姓名',
age tinyint unsigned comment '年龄',
dept_id int comment '部门id',
address varchar(10) comment '住址'
) comment '员工表';
-- 销毁表
drop table emp;
-- 新建部门表
create table dept
(
id int primary key auto_increment comment '部门工号',
name varchar(10) unique comment '部门名称'
);
-- 往员工表提娜佳数据
insert into emp value (1, '冰冰', 18, 2, '广州'),
(2, '缓缓', 18, 2, '南京'),
(3, '圆圆', 18, 2, '深圳'),
(4, '菲菲', 18, 3, '广州'),
(5, '小张', 20, 3, '深圳'),
(6, '老王', 40, 1, '广州'),
(7, '老黄', 60, null, null);
-- 往部门表添加数据
insert into dept value (1, '人事部'),
(2, '销售部'),
(3, '财务部');
5.1 内连接
显示两张表的交集部分的数据
sql
-- 内连接:显示两张表交集部门的数据
-- 需求:查询员工姓名,年龄以及相关部门
-- 隐式内连接
-- 连接的表:emp, dept
-- 查询连接条件:e.dept_id = d.id
select e.name, d.name from emp e , dept d where e.dept_id = d.id;
-- 显示内连接
-- 连接的表:emp, dept
-- 查询连接条件:e.dept_id = d.id
-- inner 可省略不写
select e.name, d.name from emp e inner join dept d on e.dept_id = d.id;
select e.name, d.name from emp e join dept d on e.dept_id = d.id;
5.2 外连接
显示一张表的所有数据以及两张表的交集部分数据
sql
-- 外连接:显示整张表的数据以及两张表的交集数据
-- 需求:显示员工表的所有数据,以及员工表在部门表所处的部门数据
-- 左外连接实现:
select * from emp e left outer join dept d on e.dept_id = d.id;
-- 需求:显示部门表的数据,以及该部门内的员工信息
-- 右外连接实现
select * from emp e right outer join dept d on e.dept_id = d.id;
-- 也可以左外连接实现
select * from dept d left outer join emp e on d.id = e.dept_id;
5.3 自查询
sql
-- 自查询
-- 查询员工名字以及所处部门,没有部门的也要显示
select e.name, d.name from emp e left outer join dept d on e.dept_id = d.id;
5.4 联合查询
将多张表查询的结果合并成一张表并返回该表
java
-- 联合查询
-- union all:即将两张表直接合并并且返回
-- 去掉关键字all即可实现数据去重在返回
-- 联合查询:即将多次查询的结果合并成一张表显示出来
-- 注意:联合查询的多张表查询的内容(查询的字段内容)必须保持一致,不然会报错无法查询
-- 如:查询emp表的id、name,而dept表一样有id、name,故可以查询成功,将两张表的数据内容合并成一张表并返回
select e.id, e.name from emp e
union
select * from dept d;
-- 错误案例:
-- 此时两张表里面的字段内容并不保持一致,故要同时查询两张表的所有内容并合成一张表返回会失败
select * from emp
union
select * from dept;
-- 案列:查询emp表在广州工作和年龄小于20的员工
select * from emp where address = '广州'
union
select * from emp where age < 20;
5.5 子查询
SQL查询语句嵌套查询即子查询
-- 子查询 -- sql查询语句中嵌套查询即子查询 -- 可嵌套在from、where、 -- 1.标量子查询:查询返回的结果为单个 -- 2.行子查询:查询返回结果为一行 -- 3.列子查询:查询返回结果为一列 -- 4.表子查询:查询返回结果为表
5.5.1 标量子查询
子查询返回的结果为单个数据
sql
-- 标量子查询
-- 需求:查询销售部的员工信息
-- 1.先查询销售部id
select id from dept where name = '销售部';
-- 2.后通过返回的销售部id查询该部门内地员工信息
select * from emp where dept_id = ( select id from dept where name = '销售部' );
5.5.2 列子查询
子查询返回结果为一列(即多行)数据
sql
-- 列子查询
-- 关键字:in:在该范围内任意一个满足即可
-- not in:不再该范围内的数据即可
-- all:所有
-- any、some:任意一个
-- 需求:查询多个部门的所有员工信息
-- 1.先查询销售部和财务部id
select id from dept where name in ('销售部','财务部');
-- 2.通过返回结果获取该部门内的所有员工信息
select * from emp where dept_id in ( select id from dept where name = '销售部' or name = '财务部') ;
-- 需求:查询比财务部所有员工年龄都大的员工信息
-- 1.先获取销售部所有员工
select id from dept where name = '财务部';
-- 2.获取销售部所有员工年龄
select age from emp where dept_id = ( select id from dept where name = '财务部' );
-- 3.获取比以上年龄都大的员工信息
select name, age from emp where age > all (select age from emp where dept_id = ( select id from dept where name = '财务部' ));
-- 需求:查询比财务部任意一人年龄小的员工
-- 1.获取财务部id
select id from dept where name = '财务部';
-- 2.获取财务部的所有年龄
select age from emp where dept_id = (select id from dept where name = '财务部');
-- 3.比任意一人年龄都大,关键字any 或者 some
select name ,age from emp where age > any (select age from emp where dept_id = (select id from dept where name = '财务部'));
select name ,age from emp where age < some (select age from emp where dept_id = (select id from dept where name = '财务部'));
5.5.3 行子查询
子查询返回的结果为一行数据(即多列)
sql
-- 行子查询
-- 需求:查询与冰冰的年龄及所处部门相同的员工信息
-- 1.查询冰冰年龄及所处部门id
select age, dept_id from emp where name = '冰冰';
-- 2.通过返回的一行信息查询与该行信息完全一致的员工信息
select name, age, dept_id from emp where age = 18 and dept_id = 2;
select name, age, dept_id from emp where (age, dept_id) = (select age, dept_id from emp where name = '冰冰');
5.5.4 表子查询
子查询返回结果为一个表
sql
-- 表子查询
-- 需求:查询冰冰和菲菲年龄以及部门相同的员工信息
-- 1.查询冰冰和菲菲的信息
select age, dept_id from emp where name in ('菲菲', '冰冰');
-- 2.查询与以上信息相同的员工信息
select * from emp where (age, dept_id) in (select age, dept_id from emp where name in ('菲菲', '冰冰'));
6. 事务
MySQL中的事务是一种机制,也是一个操作序列,它包含了一组数据库操作命令。这些命令被作为一个整体一起向系统提交或撤销操作请求,即这一组数据库命令要么都执行,要么都不执行。事务是一个不可分割的工作逻辑单元,特别是在数据库系统上执行并发操作时,事务被视为最小的控制单元。它特别适用于多用户同时操作的数据库系统的场景,如银行、保险公司及证券交易系统等,通过事务的整体性来确保数据的一致性。
事务需要符合以下特点:
- 原子性(Atomicity):一个事务必须被视为一个不可分割的最小工作单元。整个事务中的所有操作要么全部提交成功,要么全部失败。对于一个事务来说,不可能只执行其中的一部分操作。
- 一致性(Consistency):一致性是指事务将数据库从一种一致性状态转换到另外一种一致性状态。在事务开始之前和事务结束后,数据库数据的完整性没有被破坏。
- 隔离性(Isolation):隔离性要求一个事务对数据库中数据的修改,在未提交完成前对于其它事务是不可见的。这确保了并发执行的事务之间不会相互干扰。
- 持久性(Durability):一旦事务提交,对数据的修改就是永久的,即使系统出现故障也不会丢失数据。
以一个简单的例子来理解事务:假设要向公司添加一名新员工,这个过程可能包括在员工数据库中为员工创建一条新记录(分配员工ID、分配岗位等),为新员工分配部门,以及建立员工的工资和奖金记录。所有这些操作都需要在一个事务中完成,以确保数据的完整性和一致性。如果其中任何一个步骤失败,整个事务都会回滚,所有已经执行的操作都会被撤销,数据库将回到事务开始前的状态。
sql
-- 事务
insert into account value (1, 'zhangsan', 1000);
insert into account value (2, '李四', 2000);
update account set name = '张三' where name = 'zhangsan';
-- 事务的操作
-- 查看/设置事务的提交方式
-- 系统默认自动提交,默认值为1
select @@autocommit;
-- 设置事务手动提交
set @@autocommit = 0;
-- 开启事务 (start transaction / begin 都可以开启事务
start transaction ;
begin ;
-- 1.张三金额-1000
update account set money = money - 1000 where name = '张三';
-- 2.李四金额+1000
update account set money = money + 1000 where name = '李四';
-- 提交事务
commit ;
-- 回滚事务
rollback ;
并发事务问题
脏读:一个事务读取到另一个事务未提交的数据
不可重复读:同一个事务前后两次读取的数据不一致
幻读:查询时显示没有该数据,插入该数据时又显示数据已存在
sql
-- 查看事务的隔离级别
select @@transaction_isolation;
-- 设置事务的隔离级别
set transaction isolation level read uncommitted ;