——目前运行速度最快的 SQL 语言数据库之一
一、数据库介绍
1.数据库概述
数据库就是存储数据的仓库,其本质是一个文件系统,按照特定的格式将数据存储起来,用户可以对数据库中的数据进行增加,修改,删除及查询操作。
随着互联网的高速发展,大量的数据在不断的产生,伴随而来的是如何高效安全的存储数据和处理数据,而这一问题成为了信息时代的一个非常大的问题,而使用数据库可以高效的有条理的储存数据。
优点:
2.数据库分类
数据库又分为关系型数据库和非关系型数据库。
关系模型指的就是二维表格模型,而一个关系型数据库就是由二维表及其之间的联系所组成的一个数据组织。
初学阶段,我们可以先简单的将关系型数据库理解为一个Excel表格:
非关系型数据库:又被称为NoSQL(Not Only SQL ),意为不仅仅是SQL,对NoSQL 最普遍的定义是“非关联型的”,强调 Key-Value 的方式存储数据。
Key-Value结构存储: Key-value数据库是一种以键值对存储数据的一种数据库,类似Java中的map。可以将整个数据库理解为一个大的map,每个键都会对应一个唯一的值。
3.常见的数据库
关系型数据库
非关系型数据库
4.总结
二、MySQL数据库
1.MySQL数据库介绍
2.MySQL数据库的版本和安装
版本介绍
下载
MySQL是开源免费的,可以直接去官网下载最新版MySQL,下载地址如下:
安装
3.环境变量的添加
添加环境变量——在终端使用MySQL需要添加环境变量
默认的安装路径: C:\Program Files\MySQL\MySQL Server 8.0\bin
找到此电脑右键点击选择属性,弹出如下界面,选择高级系统设置,不同版本系统位置可能不太一样,耐心寻找一下。
检测环境变量是否配置成功
在底部搜索栏输入cmd,按Enter键唤出终端窗口。
输入mysql -V(V要大写),输出如下内容则配置成功。
登录MySQL数据库
输入密码
mysql --host=ip地址 --user=用户名 --password=密码
4.MySQL图形化开发工具-DataGrip
概述
DataGrip是JetBrains公司推出的管理数据库的产品,功能非常强大,可以兼容各种数据库,另外,JetBrains公司还有一款知名的IDE开发工具IDEA,用户体验非常不错。
下载地址:https://www.jetbrains.com/datagrip/download/#section=windows
安装
创建工程
点击File->New->Project新建DataGrip工程
输入项目名称,点击确定。
选择新项目打开方式:This Windows(在本窗口中打开),New Windows(在新窗口中打开), Attach(附加模式)
连接数据库
点击连接名称之后的按钮可以选择所要使用的数据库
界面及书写方式调整
设置关键字大写:File-->settings-->Editor-->Code Style-->SQL-->MySql(需要设置的数据库)-->Case
5.总结
方法一:mysql -uroot -p123456
方法一:mysql -uroot –p 回车
输入密码
方法三:mysql --host=IP地址 --user=用户名 --password=密码
三、SQL语句
1.SQL语句介绍
SQL语句
结构化查询语言(Structured Query Language)简称SQL,是关系型数据库管理系统都需要遵循的规范,是数据库认识的语句。不同的数据库生产厂商都支持SQL语句,但都有自己特有内容。
举例:
普通话:各数据库厂商都遵循的ISO标准。
方言:数据库特有的关键字。
2.SQL语句分类
1、数据定义语言:简称DDL(Data Definition Language)
2、数据操作语言:简称DML(Data Manipulation Language)
3、数据查询语言:简称DQL(Data Query Language)
4、数据控制语言:简称DCL(Data Control Language)
3.SQL通用语法
1、SQL语句可以单行或多行书写,以分号结尾。
select * from students;
2、可使用空格和缩进来增强语句的可读性
select
*
from
student;
3、MySQL数据库的SQL语句不区分大小写,关键字建议使用大写
例:SELECT * FROM user; 等于 select * from user;
4、可以使用 /**/,--,# 的方式完成注释
/**/:多行注释,在注释区域内可以随意换行
-- # :单行注释,写在语句开头,换行后注释截止。
单行注释快捷键:ctrl+/
4.SQL常用数据类型
MySQL 中定义数据字段的类型对数据库的优化是非常重要的。
MySQL 支持多种类型,大致可以分为三类:数值、日期/时间和字符串(字符)类型。
数值类型
日期和时间类型
字符串类型
注意:
5.总结
字符:char,varchar
整数:int
浮点型:decimal
日期型:date,datetime
四、DDL之数据库操作:database
1.创建数据库
# 直接创建数据库,如果存在则报错
create database 数据库名;
# 如果数据库不存在则创建
create database if not exists practice1;
# 创建数据库时设置字符集
create database 数据库名 character set 字符集;
注意:一般情况下我们会使用utf8字符集进行创建,否则可能导致中文乱码情况。
2.查看MySQL服务器中所有数据库
# 查看数据库列表
show databases;
3.删除数据库
# 删除指定数据库 practice1
格式:drop database 数据库名称
drop database practice1;
4.使用数据库
# 使用数据库
格式:use 数据库名字;
use pratice;
# 查看正在使用的数据库:
select database();
5.总结
五、DDL之表操作:table
1.表的创建
# 使用create table进行数据表创建
格式:
create table if not exists 表名(
字段名1 类型(长度) [约束],
字段名2 类型(长度) [约束],
...
);
2.查看表
# 查看数据库中的所有表:
show tables;
# 查看表结构:
格式:desc 表名;
desc category;
3.删除表
# 删除数据库中的表,表必须存在:
格式:drop table 表名;
drop table category;
若表不存在则会报错:
4.修改表结构
添加字段
# 添加表结构中的字段:
格式:alter table 表名 add 列名 类型(长度) [约束];
注意:约束按需求选择添加,可以没有约束,类型必须填写,并只能填写一个类型
alter table category add `desc` varchar(20);
进行表结构查看:
注意:desc 为关键字,此时必须用中文引号 。但理论上我们再添加字段时不需要给字段名添加``
这里这样写是因为desc是关键字(具有特殊功能或含义的字符),如果非关键字,即可使用如下写法。
修改字段
# 修改表结构中的列名
格式:alter table 表名 change 旧列名 新列名 类型(长度) 约束;
# 为分类表的分类描述字段更换为description varchar(30)
alter table category change `desc` description varchar(30);
删除字段
# 删除表结构中的列名
格式:alter table 表名 drop 列名;
# 删除分类表中description这列
alter table category drop description;
修改表名
# 修改表名
格式:rename table 表名 to 新表名;
# 为分类表category改名成 category2
rename table catgory to catgory2;
5.总结
alter table 表名 add 列名 类型(长度) [约束];
alter table 表名 change 旧列名 新列名 类型(长度) 约束;
alter table 表名 drop 列名;
rename table 表名 to 新表名;
六、DML数据操作语言
1.插入表记录
# 向表中插入数据
格式:insert into 表 (字段1,字段2,字段3...) values(值1,值2,值3...);
insert into category2(cid, cname) values('c001','电器');
# 向表中插入所有字段,字段的顺序为创建表时的顺序
格式:insert into 表 values(值1,值2,值3..);
insert into category2 values('c002','服饰',2);
# 一次添加多条数据信息
格式:insert into 表 (字段1,字段2,字段3...) values(值1,值2,值3...),(值1,值2,值3...)…;
insert into category2 (cid, cname) values('03','家电'),('04','调料'),('05',null);
格式:insert into 表 values(值1,值2,值3..),(值1,值2,值3..),…;
insert into category2 values('06','文体',4),('07','粮油',5);
2.更新表记录
# 更新所有记录的指定字段
格式:update 表名 set 字段名=值,字段名=值,...;
update category2 set cname = '饮品'; # 将所有行的cname改为'饮品'
# 更新符号条件记录的指定字段
格式:update 表名 set 字段名=值,字段名=值,... where 条件;
update category2 set cname = '牛奶' where cid = 'c001'; # 将cid为c001的cname修改为牛奶
注意:
1、列名的类型与修改的值要一致
2、修改值得时候不能超过最大长度
3、除了数值类型外,其它的字段类型的值必须使用引号引起
3.删除记录
# 按条件删除记录
格式:delete from 表名 [where 条件];
delete from category where cid = '005‘; # 删除cid为005的纪录
# 清空表记录
格式:truncate table 表名;
truncate category; # 清空表数据
注意:
清空表记录和删除表记录的区别:
使用delete删除表记录时,主键自增序列不清零。
使用truncate删除表记录时,主键自增序列清零。
4.总结
delete from 表名 [where 条件];
truncate category;
七、SQL约束
1.主键约束
1、PRIMARY KEY 约束唯一标识数据库表中的每条记录。
2、主键必须包含唯一的值。
3、主键列不能包含 NULL 值。
4、每个表都应该有一个主键,并且每个表只能有一个主键。
遵循原则:
1)主键应当是对用户没有意义的
2)永远也不要更新主键。
3)主键不应包含动态变化的数据,如时间戳、创建时间列、修改时间列等。
4) 主键应当由计算机自动生成。
添加主键约束:
创建表时,在字段描述处,声明指定字段为主键:
删除主键约束:
如需撤销 PRIMARY KEY 约束,请使用下面的 SQL:
alter table persons1 drop primary key ;
2.自动增长
我们通常希望在每次插入新记录时,数据库自动生成字段的值。
我们可以在表中使用 auto_increment(自动增长列)关键字,自动增长列类型必须是整型,自动增长列必须为键(一般是主键)。
下列 SQL 语句把 "persons2" 表中的 "id" 列定义为 auto_increment 主键
向persons添加数据时,可以不为Id字段设置值,也可以设置成null,数据库将自动维护主键值:
insert into persons2(first_name,last_name) values('Bill','Gates');
insert into persons2(id,first_name,last_name) values(null,'Bill','Gates’);
3.非空约束
NOT NULL 约束强制列不接受 NULL 值。
NOT NULL 约束强制字段始终包含值。这意味着,如果不向字段添加值,就无法插入新记录或者更新记录。
下面的 SQL 语句强制 "id" 列和 "last_name" 列不接受 NULL 值:
4.唯一约束
UNIQUE 约束唯一标识数据库表中的每条记录。
UNIQUE 和 PRIMARY KEY 约束均为列或列集合提供了唯一性的保证。
PRIMARY KEY 拥有自动定义的 UNIQUE 约束。
请注意:
每个表可以有多个 UNIQUE 约束,但是每个表只能有一个 PRIMARY KEY 约束。
5.默认值约束
默认 DEFAULT: 当不填写字段对应的值会使用默认值,如果填写时以填写为准。
6.总结
1.主键约束:唯一标示,不能重复,不能为空。
1)主键应当是对用户没有意义的
2)永远也不要更新主键。
3)主键不应包含动态变化的数据,如时间戳、创建时间列、修改时间列等。
4) 主键应当由计算机自动生成。
我们可以在表中使用 auto_increment(自动增长列)关键字,自动增长列类型必须是整型,自动增长列必须为键(一般是主键)。
NOT NULL 约束强制列不接受 NULL 值。
UNIQUE 约束唯一标识数据库表中的每条记录。
UNIQUE 和 PRIMARY KEY 约束均为列或列集合提供了唯一性的保证。
PRIMARY KEY 拥有自动定义的 UNIQUE 约束。
如果插入数据时不指定当前字段的值,则查询该字段是否有默认值,如果有则插入默认值。
八、数据查询语言
1.简单查询
select查询 :
# 根据某些条件从某个表中查询指定字段的内容
格式:select [distinct]*| 列名,列名 from 表 where 条件
简单查询:(先创建一个表product)
# 1.查询所有的商品.
select * from product;
# 2.查询商品名和商品价格.
select pname,price from product;
# 3.查询结果是表达式(运算查询):将所有商品的价格+10元进行显示.
select pname,price+10 from product;
2.条件查询
比较查询
# 查询商品名称为“花花公子”的商品所有信息:
SELECT * FROM product WHERE pname = '花花公子';
# 查询价格为800商品
SELECT * FROM product WHERE price = 800;
# 查询价格不是800的所有商品
SELECT * FROM product WHERE price != 800;
SELECT * FROM product WHERE price <> 800;
# 查询商品价格大于60元的所有商品信息
SELECT * FROM product WHERE price > 60;
# 查询商品价格小于等于800元的所有商品信息
SELECT * FROM product WHERE price <= 800;
范围查询
# 查询商品价格在200到1000之间所有商品
SELECT * FROM product WHERE price BETWEEN 200 AND 1000;
# 查询商品价格是200或800的所有商品
SELECT * FROM product WHERE price IN (200,800);
逻辑查询
# 查询商品价格在200到1000之间所有商品
SELECT * FROM product WHERE price >= 200 AND price <=1000;
# 查询商品价格是200或800的所有商品
SELECT * FROM product WHERE price = 200 OR price = 800;
# 查询价格不是800的所有商品
SELECT * FROM product WHERE NOT(price = 800);
模糊查询
# 查询以'香'开头的所有商品
SELECT * FROM product WHERE pname LIKE '香%‘;
# 查询第二个字为'想'的所有商品
SELECT * FROM product WHERE pname LIKE '_想%‘;
非空查询
# 查询没有分类的商品
SELECT * FROM product WHERE category_id IS NULL;
# 查询有分类的商品
SELECT * FROM product WHERE category_id IS NOT NULL;
3.排序查询
# 通过order by语句,可以将查询出的结果进行排序。暂时放置在select语句的最后。
格式:SELECT * FROM 表名 ORDER BY 排序字段 ASC|DESC;
# 1.使用价格排序(降序)
SELECT * FROM product ORDER BY price DESC;
# 2.在价格排序(降序)的基础上,以分类排序(降序)
SELECT * FROM product ORDER BY price DESC,category_id DESC;
4.聚合查询
之前我们做的查询都是横向查询,它们都是根据条件一行一行的进行判断,而使用聚合函数查询是纵向查询,它是对一列的值进行计算,然后返回一个单一的值;另外聚合函数会忽略空值。
# 1、查询商品的总条数
SELECT COUNT(*) FROM product;
# 2、查询价格大于200商品的总条数
SELECT COUNT(*) FROM product WHERE price > 200;
# 3、查询分类为'c001'的所有商品的总和
SELECT SUM(price) FROM product WHERE category_id = 'c001‘;
# 4、查询分类为'c002'所有商品的平均价格
SELECT AVG(price) FROM product WHERE categ ory_id = 'c002‘;
# 5、查询商品的最大价格和最小价格
SELECT MAX(price),MIN(price) FROM product;
5.分组查询
分组查询是指使用group by字句对查询信息进行分组。
格式:SELECT 字段1,字段2… FROM 表名 GROUP BY 分组字段 HAVING 分组条件;
分组操作中的having子语句,是用于在分组后对数据进行过滤的,作用类似于where条件。
having与where的区别:
1).having是在分组后对数据进行过滤.,where是在分组前对数据进行过滤
2).having后面可以使用分组函数(统计函数),where后面不可以使用分组函数。
#1 统计各个分类商品的个数
SELECT category_id ,COUNT(*) FROM product GROUP BY category_id ;
#2 统计各个分类商品的个数,且只显示个数大于1的信息
SELECT category_id ,COUNT(*) FROM product GROUP BY category_id HAVING COUNT(*) > 1;
6.分页查询
分页查询在项目开发中常见,由于数据量很大,显示屏长度有限,因此对数据需要采取分页显示方式。例如数据共有30条,每页显示5条,第一页显示1-5条,第二页显示6-10条。
格式:
SELECT 字段1,字段2... FROM 表名 LIMIT M,N
M: 整数,表示从第几条索引开始,计算方式 (当前页-1)*每页显示条数
N: 整数,表示查询多少条数据
SELECT 字段1,字段2... FROM 表明 LIMIT 0,5
SELECT 字段1,字段2... FROM 表明 LIMIT 5,5
7.总结
SELECT 字段1,字段2... FROM 表名 LIMIT M,N
M: 整数,表示从第几条索引开始,计算方式 (当前页-1)*每页显示条数
N: 整数,表示查询多少条数据
九、多表操作
1.概述
2.表与表之间的关系
一对多关系:
常见实例:客户和订单,分类和商品,部门和员工。
一对多建表原则:在从表(多方)创建一个字段,字段作为外键指向主表(一方)的主键。
3.外键约束
现在我们有两张表“分类表”和“商品表”,为了表明商品属于哪个分类,通常情况下,我们将在商品表上添加一列,用于存放分类cid的信息,此列称为:外键。
此时“分类表category”称为:主表,“cid”我们称为主键。“商品表products”称为:从表,category_id称为外键。我们通过主表的主键和从表的外键来描述主外键关系,呈现就是一对多关系。
外键特点:
从表外键的值是对主表主键的引用。
从表外键类型,必须与主表主键类型一致。
4.一对多操作
category分类表,为一方,也就是主表,必须提供主键cid
products商品表,为多方,也就是从表,必须提供外键category_id
# 创建分类表
CREATE TABLE category
(
cid VARCHAR(32) PRIMARY KEY,
cname VARCHAR(100) #分类名称
);
# 商品表
CREATE TABLE products (
pid varchar(32) PRIMARY KEY ,
name VARCHAR(40) ,
price DOUBLE ,
category_id varchar(32),
CONSTRAINT FOREIGN KEY(category_id) REFERENCES category(cid) # 添加约束
);
#1 向分类表中添加数据
INSERT INTO category (cid ,cname) VALUES('c001','服装');
#2 向商品表添加普通数据,没有外键数据,默认为null
INSERT INTO products (pid,pname) VALUES('p001','商品名称');
#3 向商品表添加普通数据,含有外键信息(category表中存在这条数据)
INSERT INTO products (pid ,pname ,category_id) VALUES('p002','商品名称2','c001');
#4 向商品表添加普通数据,含有外键信息(category表中不存在这条数据) -- 失败,异常
INSERT INTO products (pid ,pname ,category_id) VALUES('p003','商品名称2','c999');
#5 删除指定分类(分类被商品使用) -- 执行异常
DELETE FROM category WHERE cid = 'c001';
5.总结
从表外键的值是对主表主键的引用。
从表外键类型,必须与主表主键类型一致。
3.从表中引用了主表中的数据,主表中数据不可被删除。
十、多表查询
1.多表查询
1.交叉连接查询(基本不会使用-得到的是两个表的乘积) [了解]
语法:select * from A,B;这个结果有问题是错误的----笛卡尔积
2.交集运算:内连接查询(使用的关键字 inner join -- inner可以省略)
显示内连接:select * from A inner join B on 条件;
3.差集运算:外连接查询(使用的关键字 outer join -- outer可以省略)
左外连接:left outer join
select * from A left outer join B on 条件;
右外连接:right outer join
select * from A right outer join B on 条件;
示例1准备工作:
# 创建hero表CREATE TABLE hero
(
hid INT PRIMARY KEY,
hname VARCHAR(255),
kongfu_id INT
);
# 创建kongfu表
CREATE TABLE kongfu
(
kid INT PRIMARY KEY,
kname VARCHAR(255)
);
# 插入hero数据
INSERT INTO hero VALUES(1, '鸠摩智', 9),(3, '乔峰', 1),(4, '虚竹', 4),(5, '段誉', 12);
# 插入kongfu数据
INSERT INTO kongfu VALUES(1, '降龙十八掌'),(2, '乾坤大挪移'),(3, '猴子偷桃'),(4, '天山折梅手');
内连接
# 内连接(左表存在,右表也存在的数据被保留)
SELECT hname,kname FROM hero INNER JOIN kongfu ON hero.kongfu_id = kongfu.kid;
左连接(左表存在的数据被保留)
SELECT hname,kname FROM hero LEFT OUTER JOIN kongfu ON hero.kongfu_id = kongfu.kid;
# 右连接(右表存在的数据被保留)
SELECT hname,kname FROM hero RIGHT OUTER JOIN kongfu ON hero.kongfu_id = kongfu.kid;
多表查询的结果集示意图:
示例2准备工作:
CREATE TABLE category (
cid VARCHAR(32) PRIMARY KEY ,
cname VARCHAR(50)
);
CREATE TABLE products(
pid VARCHAR(32) PRIMARY KEY ,
pname VARCHAR(50),
price INT,
flag VARCHAR(2), #是否上架标记为:1表示上架、0表示下架
category_id VARCHAR(32),
CONSTRAINT products_fk FOREIGN KEY (category_id) REFERENCES category (cid)
);
#分类
INSERT INTO category(cid,cname) VALUES('c001','家电');
INSERT INTO category(cid,cname) VALUES('c002','服饰');
INSERT INTO category(cid,cname) VALUES('c003','化妆品');
#商品
INSERT INTO products(pid, pname,price,flag,category_id) VALUES('p001','联想',5000,'1','c001');
INSERT INTO products(pid, pname,price,flag,category_id) VALUES('p002','海尔',3000,'1','c001');
INSERT INTO products(pid, pname,price,flag,category_id) VALUES('p003','雷神',5000,'1','c001');
INSERT INTO products (pid, pname,price,flag,category_id) VALUES('p004','JACK JONES',800,'1','c002');
INSERT INTO products (pid, pname,price,flag,category_id) VALUES('p005','真维斯',200,'1','c002');
INSERT INTO products (pid, pname,price,flag,category_id) VALUES('p006','花花公子',440,'1','c002');
INSERT INTO products (pid, pname,price,flag,category_id) VALUES('p007','劲霸',2000,'1','c002');
INSERT INTO products (pid, pname,price,flag,category_id) VALUES('p008','香奈儿',800,'1','c003');
INSERT INTO products (pid, pname,price,flag,category_id) VALUES('p009','相宜本草',200,'1','c003');
# 1.查询哪些分类的商品已经上架
# 内连接
SELECT DISTINCT c.cname FROM category c
INNER JOIN products p ON c.cid = p.category_id
WHERE p.flag = '1';
# 2.查询所有分类商品的个数
# 左连接
INSERT INTO category(cid,cname) VALUES('c004','奢侈品');
SELECT cname,COUNT(category_id) FROM category c
LEFT OUTER JOIN products p
ON c.cid = p.category_id
GROUP BY cname;
2.子查询
子查询:一条select语句结果作为另一条select语法一部分(查询条件,查询结果,表等)。
select ....查询字段 ... from ... 表.. where ... 查询条件
举例: 查询“化妆品”分类上架商品详情
# 子查询(作为查询条件)
SELECT * FROM products p
WHERE p.category_id =
(
SELECT c.cid FROM category c
WHERE c.cname='化妆品'
);
# 作为另一张表
SELECT * FROM products p ,
(SELECT * FROM category WHERE cname='化妆品') c
WHERE p.category_id = c.cid;
# 查询“化妆品”和“家电”两个分类上架商品详情
SELECT * FROM products p
WHERE p.category_id in
(
SELECT c.cid FROM category c
WHERE c.cname='化妆品' or c.name='家电'
);
3.自查询
自查询:左表和右表是同一个表,根据连接查询条件查询两个表中的数据。
示例:
创建tb_areas表:
CREATE TABLE tb_areas
(
id VARCHAR(30) NOT NULL PRIMARY KEY,
atitle VARCHAR(30),
pid VARCHAR(30)
);
插入数据:
INSERT INTO test.tb_areas (id, atitle, pid) VALUES ('1', '广东省', 'null');
INSERT INTO test.tb_areas (id, atitle, pid) VALUES ('2', '河南省', 'null');
INSERT INTO test.tb_areas (id, atitle, pid) VALUES ('3', '深圳市', '1');
INSERT INTO test.tb_areas (id,atitle, pid) VALUES ('4', '广州市', '1');
INSERT INTO test.tb_areas (id,atitle, pid) VALUES ('5', '南山区', '3');
INSERT INTO test.tb_areas (id, atitle, pid) VALUES ('6', '宝安区', '3');
INSERT INTO test.tb_areas (id, atitle, pid) VALUES ('7', '越秀区', '4');
INSERT INTO test.tb_areas (id, atitle, pid) VALUES ('8', '天河区', '4');
插入地区数据后:
select city.* form areas as city inner join areas as province on city.pid = province.aid where province.atitle = '广东省'
3.总结
1.交集运算:内连接查询(使用的关键字 inner join -- inner可以省略)
内连接:select * from A inner join B on 条件;
2.差集运算:外连接查询(使用的关键字 outer join -- outer可以省略)
左连接:left outer join
select * from A left outer join B on 条件;
右连接:right outer join
select * from A right outer join B on 条件;
十一、窗口函数
1.概述
MySql在8.0的版本增加了对开窗函数的支持,终于可以在MySql使用开窗函数了。
开窗函数的语法结构:
# 关键字 :partiton by 和 order by
<开窗函数> over ([partiton by <分组用列清单>]
order by <排序用列清单>)
MySql中支持的窗口函数有很多,这里重点给大家介绍三个:row_number(),rank(),dense_ra
(在本人的另一篇博客中,对窗口函数做了更加全面详细的讲解,想深入了解窗口函数的小伙伴,可以参考:掌握MySQL窗口函数window functions这一篇就够了!(详解+示例+代码,简单粗暴))
窗口函数介绍 :
row_number(),rank(),dense_rank()这三个函数都是用于返回结果集的分组内每行的排名
三者区别:
row_number:不管排名是否有相同的,都按照顺序1,2,3…..n
rank:排名相同的名次一样,同一排名有几个,后面排名就会跳过几次
dense_rank:排名相同的名次一样,且后面名次不跳跃
2.案例
数据准备:
create table employee (empid int,ename varchar(20) ,deptid int ,salary decimal(10,2));
insert into employee values(1,'刘备',10,5500.00),(2,'赵云',10,4500.00),(2,'张飞',10,3500.00),(2,'关羽',10,4500.00),(3,'曹操',20,1900.00),(4,'许褚',20,4800.00),(5,'张辽',20,6500.00),(6,'徐晃',20,14500.00),(7,'孙权',30,44500.00),(8,'周瑜',30,6500.00),(9,'陆逊',30,7500.00);
对employee表中按照deptid进行分组,并对每一组的员工按照薪资进行排名:
SELECT
empid,
ename,
deptid,
salary,
row_number() over (PARTITION BY deptid ORDER BY salary DESC) AS row_number1,
rank() OVER (PARTITION BY deptid ORDER BY salary desc) AS rank2,
dense_rank() OVER (PARTITION BY deptid ORDER BY salary desc) AS dense_rank3
FROM
employee;
TOPN
对employee表中按照deptid进行分组,并对每一组的员工按照薪资进行排名,取各组中的前两名员工信息
select *
From
(SELECT
empid,
ename,
deptid,
salary,
rank() over (PARTITION BY deptid ORDER BY salary DESC) AS row_number1
FROM
employee
) t
Where t.row_number1 <3;
3.总结
十二、事务
1.概述:
事务(transaction)指的是逻辑上的一组操作, 组成该操作的各个逻辑单元, 要么全部执行成功, 要么全部执行失败.
大白话: 同生同死.
名词解释:
一组操作: 张三 -> 李四, 转1000元
逻辑单元:
逻辑单元1: 张三账户 - 1000元
逻辑单元2: 李四账户 + 1000元
2.事务相关的SQL语句:
start transaction; 或者 begin; 开启事务
commit; 提交事务, 即: 保存结果.
rollback; 事务回滚, 相当于把数据还原到事务执行之前的状态.
select @@transaction_isolation; 查看事务的隔离级别.
set session transaction isolation level read uncommitted; # 临时设置事务的隔离级别
3.事务的特点: ACID
原子性: 指的是组成事务的各个逻辑单元已经是最小单位, 不可分割.
一致性: 指的是事务执行前后, 数据结果应该保持一致.
隔离性(Isolation): 指的是一个事务在执行期间, 不应该受到其它事务的干扰.
持久性: 指的是事务执行后, 结果会被永久保存到数据表中.
如果1个事务在执行期间, 受到了其它事务的干扰, 可能会发生一些列的问题:
关于写:
丢失更新.
关于读:
脏读, 不可重复读, 虚读.
细节:
1. MySQL默认开启了事务的自动提交功能, 每个SQL语句都是1个单独的事务, 执行之后, 会自动提交结果.
2. 隔离级别主要有4个, 分别是: read uncommitted, read committed, repeatable read, serializable
read uncommitted:
会发生脏读, 不可重复读, 虚读.
read committed:
会发生不可重复读, 虚读. 解决了: 脏读
repeatable read:
会发生虚读. 解决了: 脏读, 不可重复读
serializable:
串行化读法, 加锁的思路, 可以解决所有.
3. MySQL数据库的默认隔离级别是: repeatable read
扩展:
脏读解释: 也叫, 读-未提交
一个事务读取到了另一个事务还没有来得及提交的事务, 导致多次查询结果不一致. 即: 事务影响事务了.