第5步---MySQL的DQL查询语句
DQL 数据库查询语言
1.基本的查询语句
1.完整得查询得语句
简化版的查询语句
select * from 表名 where 条件;
2.创建用于测试的表
1.创建测试数据
-- =================================DQL=================================
-- 创建测试表
DROP TABLE IF EXISTS product;
CREATE TABLE IF NOT EXISTS product(
pid int PRIMARY KEY auto_increment COMMENT '商品编号',
pname VARCHAR(20) not null COMMENT '商品名称',
price DOUBLE COMMENT '价格',
category_id VARCHAR(20) COMMENT '商品类别'
)-- 添加测试数据
INSERT INTO product VALUES
(NULL,'苹果',5000,'c001'),
(NULL,'香蕉',50,'c001'),
(NULL,'西红柿',6000,'c001'),
(NULL,'西瓜',3000,'c001'),
(NULL,'杨桃',5500,'c001'),
(NULL,'手机',7000,'c001');INSERT INTO product VALUES
(NULL,'苹果',5000,'c002'),
(NULL,'香蕉',50,'c002'),
(NULL,'西红柿',6000,'c002'),
(NULL,'西瓜',3000,'c002'),
(NULL,'杨桃',5500,'c002'),
(NULL,'手机',7000,'c002');INSERT INTO product VALUES
(NULL,'苹果',5000,'c003'),
(NULL,'香蕉',50,'c003'),
(NULL,'西红柿',6000,'c003'),
(NULL,'西瓜',3000,'c003'),
(NULL,'杨桃',5500,'c003'),
(NULL,'手机',7000,'c003');INSERT INTO product VALUES
(NULL,'苹果',5000,'c004'),
(NULL,'香蕉',50,'c004'),
(NULL,'西红柿',6000,'c004'),
(NULL,'西瓜',3000,'c004'),
(NULL,'杨桃',5500,'c004'),
(NULL,'手机',7000,'c004');
2.基本的查询
-- 查询所有的数据
SELECT * FROM product;-- 查询指定的列的数据
SELECT pid,pname ,price,category_id FROM product;
SELECT pid,pname FROM product;-- 起表别名
-- 多表查询中是可以给的
SELECT * FROM product p;
SELECT * FROM product as p;-- 列别名
SELECT pid AS ppid FROM product;
SELECT pid AS 编码 FROM product;-- 去重
SELECT DISTINCT price FROM product;-- 去除所有列都一样的数据
SELECT DISTINCT * FROM product;-- 表达式查询
SELECT price ,price+10 new_price FROM product;
3.运算符
1.算数运算符:加减乘除 /或者div %或者mod
2.比较:条件查询。null和所有的值都是不相等的。
3.逻辑:
4.位:
3.1算数运算符
-- =============================算数运算符号=======================
-- 基本操作
SELECT 6+4;
SELECT 6-4;
SELECT 6*4;
SELECT 6/4;
SELECT 6%4;
SELECT 6 div 4;
SELECT 6 mod 4;-- 所有的商品+10元
SELECT price ,price+10 new_price FROM product;-- 所有的商品增加10%元
SELECT price ,price*(1.1) new_price FROM product;-- 所有的商品+10元
SELECT price ,price+10 new_price FROM product;-- 所有的商品增加10%元
SELECT price ,price*(1.1) new_price FROM product;-- 找苹果商品的所有的信息
SELECT *FROM product WHERE pname ='苹果';-- 找出价格为5000的商品
SELECT *FROM product WHERE price =5000;-- 查询价格不是5000的商品
SELECT *FROM product WHERE price !=5000;
SELECT *FROM product WHERE price <>5000;
SELECT *FROM product WHERE not price =5000;
SELECT *FROM product WHERE price not in (5000);-- 查询价格> 5000的商品
SELECT *FROM product WHERE price > 5000;-- 查询价格5000到7000之间的的商品
SELECT *FROM product WHERE price BETWEEN 5000 AND 7000;
SELECT *FROM product WHERE price >=5000 AND price <= 7000;-- 查询价格5000或7000的商品
SELECT *FROM product WHERE price =5000 or price = 7000;
SELECT *FROM product WHERE price in (5000 , 7000);-- 查询含有果的词
-- %任意字符
-- 前面任意
SELECT *FROM product WHERE pname LIKE '%果';
-- 后面任意
SELECT *FROM product WHERE pname LIKE '果%';
-- 前后任意
SELECT *FROM product WHERE pname LIKE '%果%';-- 下划线匹配单个字符
-- 查询第二个字含有果的词
SELECT *FROM product WHERE pname LIKE '_果%';注意:坚决不能使用等号!!!
-- 查询类别不为null的所有的数据
SELECT *FROM product WHERE category_id IS NOT NULL;-- 查询类别为null的所有的数据
SELECT *FROM product WHERE category_id IS NULL;-- 求几个值的最小值
SELECT LEAST(10,20,5) as small_number;-- 求几个值的最大值
SELECT GREATEST(10,20,5) as small_number;求最大值或者是最小值的时候要是存在null的话结果直接就是null不是我们需要的值。
求最大值或者是最小值的时候要是存在null的话结果直接就是null不是我们需要的值。
3.2位运算符
主要是对二进制的相关的操作
-- =============================位相关操作===============================
-- 位与
SELECT 3 &5;
-- 0011
-- 0101
-- 结果:0001 全是1的时候才全是1-- 位或
-- 不是0就是1
SELECT 3 | 5;-- 右移位
SELECT 2>>1;-- 左移位
SELECT 2<<1;-- 位取反
-- 1变0,0变1,变的很大的数的原因是2是32位的数字
SELECT ~2;
4.基本查询-排序
排序
-- ===================================排序和分页====================================
-- 按照降价降序
-- 默认升序
SELECT * FROM product ORDER BY price;
SELECT * FROM product ORDER BY price ASC;
-- 降序
SELECT * FROM product ORDER BY price DESC;-- 价格降序 分配升序
SELECT * FROM product ORDER BY price DESC,category_id ASC;-- 查询所有的价格 去重
SELECT DISTINCT price FROM product ORDER BY price ASC;
5.基本查询-聚合操作
下面的操作是针对不同的列的相关的操作
count 行数
sum 数值和-- ==========================================聚合操作===================================-- 商品条数
-- * 不为空的行
SELECT COUNT(*) FROM product ;SELECT COUNT(pid) FROM product ;-- 价格大于5000的商品的总条数SELECT COUNT(pid) FROM product WHERE price > 5000;-- 查询c001商品的总价格SELECT SUM(price) FROM product WHERE category_id ='c001';-- 查询商品的最大价格SELECT Max(price) FROM product ;-- 查询商品的最小价格SELECT Min(price) FROM product ;-- 平均价格SELECT Avg(price) FROM product ;-- 求某个类的平均价格SELECT Avg(price) FROM product WHERE category_id ='c001';-- 求最大和最小价格SELECT Min(price),Max(price) FROM product ;
对null的操作
-- ==========================================聚合操作-对null的操作===================================
-- 创建测试表
DROP TABLE IF EXISTS test_null;
CREATE TABLE IF NOT EXISTS test_null(
c1 VARCHAR(20),
c2 int
);
-- 创建测试数据
INSERT INTO test_null VALUES
('aaa',3),
('bbb',4),
('ccc',NULL),
(NULL,5);-- 测试
-- 要是选中的列是null的视而不见的,不进行统计
SELECT COUNT(*) ,COUNT(1) ,COUNT(c1),COUNT(c2)FROM test_null;-- 要是null的话,求平均值的时候就当作不存在的
SELECT max(c2) ,min(c2) ,avg(c2)FROM test_null;
6.聚合操作-分组查询
多了一个分组。可以一个或者是多个分组,可以采用having进行相关的分组的操作
必须商品中的类别就是一个分组的条件。
-- ==========================================聚合操作-分组查询===================================-- 统计 不同分类的商品
-- 相当于把相同类别的设置成了一张表,分别对其进行求和的操作
SELECT category_id,COUNT(*) FROM product GROUP BY category_id;SELECT category_id ,COUNT(1) FROM product GROUP BY category_id;
下面是对分组过程的介绍。分组一般是和聚合是在一起进行使用的。
7.聚合操作-分组筛选
-- ==========================================聚合操作-分组筛选===================================
-- 统计每个类别的商品的数量并且将输出每个类别中商品数量大于5的类别的id和商品数量
SELECT category_id ,COUNT(1) FROM product GROUP BY category_id HAVING COUNT(1)>5 ;
下面是执行的顺序
可以加上对应的排序的字段
-- 加上排序
SELECT category_id ,COUNT(1) FROM product GROUP BY category_id HAVING COUNT(1)>5 ORDER BY category_id DESC ;
8.基本查询-分页查询
limit n:显示前n条
limit m,n:从m+1条开始显示n条
-- ==========================================基本查询-分页操作===================================
-- 显示前5条数据
SELECT * FROM product LIMIT 5;-- 从第4条开始显示5条
SELECT * FROM product LIMIT 3,5;-- 模拟分页
-- (当前页-1)*页大小
SELECT * FROM product LIMIT 0,5;SELECT * FROM product LIMIT 5,5;
9.将查询结果插入到新的表
将后面的结果插入到前面的表
-
字段一致
-
类型一致
-
要插入的表必须先存在
-- ==========================================基本查询-插入新的表中===================================-- 创建测试的表
CREATE TABLE IF NOT EXISTS product2(
id int PRIMARY key ,
pname VARCHAR(20) ,
price DOUBLE
);-- 插入到上面的表
INSERT INTO product2(id,pname,price) SELECT pid,pname,price FROM product;
10.基本查询-总结
-
简单查询:不加任何的条件。全表。字段和*。别名查询。列和表的别名。
-
去重查询:distinct。去重重复的列或者重复的行。
-
运算符:算数,比较,逻辑和位。
默认的是升序asc。
特点:如果order by后面跟一个字段,只会按照该字段的值进行排序。其他的字符是没有排序的。
聚合查询操作:
count(1)等价于count(*)
注意有null的值就不进行相关的操作,
分组操作:
-
将一个表拆分成多个表
-
分组的时候可以根据多个字段进行分组。字段相同的分到一个组,多个字段相同也是可以分到一个组中。
-
分完组之后后面只能跟分组字段和聚合操作
-
一般情况下聚合函数和分组函数聚合在一起使用
-
后续的操作必须采用having进行相关的聚合的操作
分页字段:limit
书写顺序:
select 字段 from 表
where 条件
group by 分组
having 筛选(必须根据分组的条件)
order by 排序字段
limit 分页
执行顺序
from 从哪个表中进行查询
where 筛选查询的结果group by 分组统计
count 执行聚合操作
having 筛选聚合的东西
select 进行查询
order by 排序limit 进行筛选
11.中级查询-sql中级操作
-- =================================中级查询=====================
-- 创建测试数据
DROP TABLE IF EXISTS student;
CREATE TABLE IF NOT EXISTS student(
id INT,
name VARCHAR(20),
gender VARCHAR(20),
chinese INT,
english INT,
math INT
);INSERT INTO student(id,name,gender,chinese,english,math) VALUES(1,'张三','男',89,79,70);
INSERT INTO student(id,name,gender,chinese,english,math) VALUES(2,'李四','女',89,99,80);
INSERT INTO student(id,name,gender,chinese,english,math) VALUES(3,'王五','男',79,69,90);
INSERT INTO student(id,name,gender,chinese,english,math) VALUES(4,'赵六','女',89,79,40);
INSERT INTO student(id,name,gender,chinese,english,math) VALUES(5,'陈二','男',99,89,50);
INSERT INTO student(id,name,gender,chinese,english,math) VALUES(6,'王瓜','女',49,99,60);
INSERT INTO student(id,name,gender,chinese,english,math) VALUES(7,'轧盖','男',59,89,70);
INSERT INTO student(id,name,gender,chinese,english,math) VALUES(8,'赵恒','女',69,49,80);
INSERT INTO student(id,name,gender,chinese,english,math) VALUES(8,'赵恒','女',69,49,80);-- 查询所有的数据SELECT * FROM student;-- 查询表中所有的学生的姓名和对应的英语成绩SELECT name,english FROM student ;-- 去重SELECT DISTINCT * FROM student ;-- 统计学生的总分SELECT DISTINCT FROM student ;-- 先进行去重了然后对不同学生的进行求总分-- 分组的时候必须进行起别名SELECT name, sum(chinese + english + math) AS total FROM
(SELECT * FROM student ) tmp GROUP BY name-- 对上面的总分加上10SELECT name, sum(chinese + english + math + 10) AS total FROM
(SELECT * FROM student ) tmp GROUP BY name-- 找出英语大于90分的SELECT * FROM student WHERE english>90;-- 查出总分大于200的-- 聚合操作的求和SELECT name,sum(chinese + english + math ) total FROM (SELECT DISTINCT * FROM student ) tmp GROUP BY name HAVING total > 200;-- 非聚合操作的求和-- 此时不能用前面的别名但是having是可以。原因是执行顺序的原因SELECT DISTINCT name,(chinese + english + math) total FROM student WHERE (chinese + english + math)>200;-- 找出英语在80-90之间的SELECT * FROM student WHERE english >=80 and english <=90;SELECT * FROM student WHERE english BETWEEN 80 AND 90;-- 找出英语不在80-90之间的SELECT * FROM student WHERE english NOT BETWEEN 80 AND 90;SELECT * FROM student WHERE NOT (english BETWEEN 80 AND 90);SELECT * FROM student WHERE NOT (english >=80 and english <=90);SELECT * FROM student WHERE english <80 OR english >90;-- 查询数学是70和50的同学SELECT * FROM student WHERE math = 70 OR math =50;SELECT * FROM student WHERE math = IN (70,50);-- 查询数学是不是70或50的同学SELECT * FROM student WHERE math != 70 AND math !=50;SELECT * FROM student WHERE math NOT IN (70,50);-- 查询所有姓王的英语成绩SELECT name,english FROM student WHERE name LIKE '%王';-- 查询总分是238并且姓张的同学的信息SELECT * FROM student WHERE name like '张%' AND (chinese + english + math)=238;-- 按照分数从高到低的顺序查询并显示出来SELECT id,name,SUM(english+chinese+math) AS count ,gender FROM (SELECT DISTINCT * FROM student) s GROUP BY id ORDER BY count;-- 按照性别进行查询并统计男和女的顺序,根据性别进行降序输出SELECT gender,COUNT(gender) AS count FROM student GROUP BY gender HAVING count >=5 ORDER BY count;
12.正则表达式
定义了一些相关的字符串的匹配的规则,本身是一个字符串,回匹配一些列符合某个句法的规则的字符串。常常用于检索,替换那些符合规则恶的文本,
可以采用regexp关键字支持正则表达式
^ 匹配输入字符串开始位置
$ 匹配输入字符串结束位置
. 匹配除了\n之外的任何单个字符
[...] 字符集合,包含的任意一个字符。[abc]可以匹配 plain中的a
[^...]负值字符集合。匹配未包含的任意字符
p1|p2|p3 匹配p1 p2或者 p3
* 0次或者多次
+ 匹配前面子表达式一次或者多次
{n}
{n,m}
下面是演示在项目中的基本的使用
-- ====================正则表达式-- 判断字符串是不是以a开头SELECT 'abc' REGEXP '^a';-- $判断以某个字符结尾的SELECT 'abc' REGEXP 'a$';SELECT 'abc' REGEXP 'c$';
下面是常见的正则匹配
-- ======================下面是真正的项目中的使用-- 找以苹开始的所有的信息SELECT * FROM product WHERE pname REGEXP '^苹';-- 找以国结尾的数据SELECT * FROM product WHERE pname REGEXP '国$';-- .可以匹配任意单个字符SELECT 'abc' REGEXP '.a';-- 0SELECT 'abc' REGEXP '.b';-- 1SELECT 'abc' REGEXP '.c'; -- 1-- [...]匹配括号内的任意单个字符SELECT 'abc' REGEXP '[ade]'-- 1SELECT 'abc' REGEXP '[xyz]'-- 0-- [^..]匹配括号内的任意单个字符SELECT 'a' REGEXP '[^ade]'; -- 0SELECT 'abc' REGEXP '[^ade]'; -- 1SELECT 'abc' REGEXP '[^xyz]'; -- 1-- * 匹配0到多个字符SELECT 'stab' REGEXP '.ta*b'; -- 1SELECT 'stb' REGEXP 'ta*b'; -- -- a+ 字符a出现一次或者多次SELECT 'stab' REGEXP '.ta+b'; -- 1SELECT 'stb' REGEXP 'ta+b'; -- 0-- a? 匹配0个或者1个字符SELECT 'abc' REGEXP 'a?'SELECT 'bc' REGEXP 'a?'-- a1 |a2匹配a1或者a2SELECT 'a' REGEXP 'a|b';SELECT 'c' REGEXP 'a|b';
下面是剩下的常见的正则匹配的规则
-- 以a或者b开头的SELECT 'abc' REGEXP '^(a|b)';SELECT 'cd' REGEXP '^(a|b)';-- a{m} 匹配m个aSELECT 'aaab' REGEXP 'a{4}'; -- 0-- a{m,} 至少出现m次SELECT 'aaaa' REGEXP 'a{3}';-- 1SELECT 'aaaa' REGEXP 'a{5}';-- 0-- a{m,n} 至多n,至少出现m次SELECT 'aaaa' REGEXP 'a{4,5}';-- 1-- (ab)必须以ab整体匹配SELECT 'abc' REGEXP '(ab)';-- 1SELECT 'abc' REGEXP '(ab){2,}';-- 0
13.多表操作
表关系就是表与之间的关系
1v1的关系
-
一个学生对应一个身份证一个身份证对应一个学生
-
在一个表中就行不用分成两个表
1v多
-
部门和员工:一个部门有多个员工,一个员工只能对应一个部门
-
外键在多端的一方
多对多
-
学生和课程之间就是多对多的关系
-
演员和角色之间的关系
-
中间表的形式进行表示
外键约束
-
表的特殊的字段和主键一起配合进行使用
-
外键关联的表是从表。也就是说有外键的表是从表,没有外键的表是主表。
-
员工和部门之间的关系就是员工表是从表,部门表是主表。
-
我们可以把表的类型分为主表和从表。
主表必须存在。必须是主键。不能包含空的值。可以采用复合的外键。外键中的列数必须和主键中的列数是一致的
14.外键约束
14.1外键约束的基本操作
创建表的时候可以指定外键约束。
在创建表的时候可以采用foreign key 去指定外键。
-- 创建部门表DROP TABLE IF EXISTS dept;CREATE TABLE IF not EXISTS dept(deptno VARCHAR(20) PRIMARY key,name VARCHAR(20));DROP TABLE IF EXISTS emp;CREATE TABLE IF NOT EXISTS emp(eid VARCHAR(20) PRIMARY KEY,ename VARCHAR(20) ,age int,dept_id VARCHAR(20) ,CONSTRAINT fk FOREIGN KEY (dept_id) REFERENCES dept(deptno));
创建完表再去添加表的约束
-- 创建部门表DROP TABLE IF EXISTS dept2;CREATE TABLE IF not EXISTS dept2(deptno VARCHAR(20) PRIMARY key,name VARCHAR(20));DROP TABLE IF EXISTS emp2;CREATE TABLE IF NOT EXISTS emp2(eid VARCHAR(20) PRIMARY KEY,ename VARCHAR(20) ,age int,dept_id VARCHAR(20)
-- CONSTRAINT fk FOREIGN KEY (dept_id) REFERENCES dept(deptno)
-- );ALTER TABLE emp2 ADD CONSTRAINT fk2 FOREIGN KEY (dept_id) REFERENCES dept2(deptno);
14.2外键约束的数据
必须先给部门表进行数据插入
-- 给主表添加数据insert into dept VALUES
('1001','研发部'),
('1002','销售部'),
('1003','财务部'),
('1004','人事部');
然后给从表添加数据
-- 给从表添加数据insert into emp VALUES
('1','张三',20,'1001'),
('2','张三',20,'1002'),
('3','张三',20,'1003'),
('4','张三',20,'1004');
测试外键约束
-
失败:存在重复
-
成功:可以插入外键可以指定为null
-- 测试外键约束insert into emp VALUES ('1','张三',20,'1005');
-- null是可以的insert into emp VALUES ('1','张三',20,NULL);
删除测试
--dept数据 删除DELETE FROM dept WHERE deptno='1002';删除是拒绝的
从表的数据是可以随便删除的,删除的时候需要注意
14.3删除外键约束
采用修改表的方式进行删除
ALTER TABLE 表名 DROP FOREIGN key 外键约束名称;ALTER TABLE emp2 DROP FOREIGN key fk2;
14.4多对多外键约束
相互之间的约束
采用中间表的形式。除了中间表都是主表。
DROP TABLE IF EXISTS stu;CREATE TABLE IF not EXISTS stu(stu_id VARCHAR(20) PRIMARY key,stu_name VARCHAR(20));DROP TABLE IF EXISTS score;CREATE TABLE IF not EXISTS score(score_id VARCHAR(20) PRIMARY key,score_name VARCHAR(20));DROP TABLE IF EXISTS stu_score;CREATE TABLE IF not EXISTS stu_score(stu_id VARCHAR(20),score_id VARCHAR(20),score DOUBLE, -- 课程成绩PRIMARY key (stu_id,score_id));ALTER TABLE stu_score ADD CONSTRAINT FOREIGN KEY (stu_id) REFERENCES stu(stu_id);ALTER TABLE stu_score ADD CONSTRAINT FOREIGN KEY (score_id) REFERENCES score(score_id);
查看表模型
删除表的时候必须先删除从表。添加数据的时候先给主表添加数据
删除数据的时候先删除从表中的数据再去删除主表中的数据。
此时数据就像是添加了对应的字典的限制似的,不能直接进行删除的操作。
15.多表联合查询
15.1常见的联合查询的类型
下面是常见的连接查询的操作.
-
直接查询就是笛卡尔积
-
内连接
-
左外
-
右外
-
满外连接
创建基本的表和测试的数据
-- ============================多表查询-数据准备=============
-- 创建部门表
create table if not exists dept3(deptno varchar(20) primary key , -- 部门号name varchar(20) -- 部门名字
);-- 创建员工表
create table if not exists emp3(eid varchar(20) primary key , -- 员工编号ename varchar(20), -- 员工名字age int, -- 员工年龄dept_id varchar(20) -- 员工所属部门
);-- 给dept3表添加数据
insert into dept3 values('1001','研发部');
insert into dept3 values('1002','销售部');
insert into dept3 values('1003','财务部');
insert into dept3 values('1004','人事部');-- 给emp3表添加数据
insert into emp3 values('1','乔峰',20, '1001');
insert into emp3 values('2','段誉',21, '1001');
insert into emp3 values('3','虚竹',23, '1001');
insert into emp3 values('4','阿紫',18, '1001');
insert into emp3 values('5','扫地僧',85, '1002');
insert into emp3 values('6','李秋水',33, '1002');
insert into emp3 values('7','鸠摩智',50, '1002');
insert into emp3 values('8','天山童姥',60, '1003');
insert into emp3 values('9','慕容博',58, '1003');
insert into emp3 values('10','丁春秋',71, '1005');
15.2不加连接条件的查询
直接形成一个笛卡尔积,两个表中的数据进行相乘
a表的每一行和b表的每一行进行匹配。
冗余的数据非常多
行数=部门行数*员工行数
列数=部门列数+员工行数
-- ======交叉查询
SELECT * FROM dept3,emp3;
15.3内连接查询
交集查询
-- 采用999标准写
-- ====内连接查询
SELECT * from dept3 INNER JOIN emp3 on dept3.deptno=emp3.dept_id;-- 等价于下面的效果
-- inner可以默认不写效果是一样的
SELECT * from dept3 JOIN emp3 on dept3.deptno=emp3.dept_id;
上面查询的哪个部门有哪些员工,就是采用的内连接的形式。
-- 查询研发部门的员工
SELECT * from dept3 d JOIN emp3 e on d.deptno=e.dept_id where d.name ='研发部';-- 查询研发部和销售部的所属员工
select * from dept3 a join emp3 b on a.deptno = b.dept_id and (name = '研发部' or name = '销售部') ;
select * from dept3 a join emp3 b on a.deptno = b.dept_id and name in('研发部' ,'销售部') ; -- 查询每个部门的员工数,并升序排序
select a.*,COUNT(*) as total from dept3 a join emp3 b on a.deptno = b.dept_id GROUP BY a.deptno ; -- 查询人数大于等于3的部门,并按照人数降序排序
select a.*,COUNT(*) as total from dept3 a join emp3 b on a.deptno = b.dept_id GROUP BY a.deptno HAVING total>3 ORDER BY total DESC;
15.4外连接查询
左外和右外和全连接
oracle中是有full join的但是在MySQL中是没有的需要采用union进行连接的。
-- =================外连接查询
-- 查询哪些部门有员工,哪些部门没有员工
-- 本质就是查询所有部门的员工
SELECT * FROM dept3 d LEFT JOIN emp3 e on d.deptno=e.dept_id;-- 查询哪些员工有部门,哪些员工没有部门
SELECT * FROM dept3 d RIGHT JOIN emp3 e on d.deptno=e.dept_id;-- 合并查询的结果
SELECT * FROM dept3 d LEFT JOIN emp3 e on d.deptno=e.dept_id
UNION
SELECT * FROM dept3 d RIGHT JOIN emp3 e on d.deptno=e.dept_id;
15.5多表联合查询
多表联合查询
select from where c> all查询语句等价于下面的语句
select from where c> result1 and c> result2 and c> result3 也就是c大于所有的子查询得结果
特点:
-
与子查询中所有得结果比较才是true,否则是false
-
all可以和=,>等进行结合使用。表示大于所有得,表示等于所有得值,表示大于等于所有得值。
-- ================多表联合查询================
-- 子查询关键字-- 查询年龄大于1003部门中所有年龄员工得信息
SELECT * FROM emp3 WHERE age > all(SELECT age FROM emp3 WHERE dept_id='1003');
-- 查询不属于任何一个部门得员工信息
SELECT * FROM emp3 WHERE dept_id != all(SELECT deptno FROM dept3 );
下面是any和some
-
any:只要比其中一个值大于,小于等就行。不需要比较所有得值。只需要比较部分得值。
-
some:和any得作用是一致得。可以理解为any得别名。
-- 查询年龄大于1003部门中任意一个员工员工得信息
SELECT * FROM emp3 WHERE age > ANY(SELECT age FROM emp3 WHERE dept_id='1003' ) and dept_id !='1003';SELECT * FROM emp3 WHERE age > SOME(SELECT age FROM emp3 WHERE dept_id='1003' ) and dept_id !='1003';
15.6自关联查询
自己关联自己,就是隐式自连接得操作。可以采用内连接得操作。一张表当作多张表进行使用。
CREATE TABLE `t_sanguo` (`eid` int(11) NOT NULL AUTO_INCREMENT,`ename` varchar(30) DEFAULT NULL,`manager_id` int(11) DEFAULT NULL,PRIMARY KEY (`eid`),KEY `manager_id` (`manager_id`),CONSTRAINT `t_sanguo_ibfk_1` FOREIGN KEY (`manager_id`) REFERENCES `t_sanguo` (`eid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;INSERT INTO `sys_test`.`t_sanguo` (`eid`, `ename`, `manager_id`) VALUES (1, '刘协', NULL);
INSERT INTO `sys_test`.`t_sanguo` (`eid`, `ename`, `manager_id`) VALUES (2, '刘备', 1);
INSERT INTO `sys_test`.`t_sanguo` (`eid`, `ename`, `manager_id`) VALUES (3, '关羽', 2);
INSERT INTO `sys_test`.`t_sanguo` (`eid`, `ename`, `manager_id`) VALUES (4, '张飞', 2);
INSERT INTO `sys_test`.`t_sanguo` (`eid`, `ename`, `manager_id`) VALUES (5, '曹操', 1);
INSERT INTO `sys_test`.`t_sanguo` (`eid`, `ename`, `manager_id`) VALUES (6, '许诸', 5);
INSERT INTO `sys_test`.`t_sanguo` (`eid`, `ename`, `manager_id`) VALUES (7, '孙权', 1);
INSERT INTO `sys_test`.`t_sanguo` (`eid`, `ename`, `manager_id`) VALUES (8, '周瑜', 7);
-- ===================================自关联查询===================
SELECT * FROM t_sanguo;-- 查询每一个人物得信息并且包含领导得信息
-- 就是左表得manager_id等于右表的eid
SELECT t1.*,t2.eid '领导编号' , t2.ename '领导名称' FROM t_sanguo t1 LEFT JOIN t_sanguo t2 ON t1.manager_id=t2.eid;-- 擦汗寻所有人物和上级和上上级
SELECT t.eid,t.ename ,temp.eid '上级领导编号' ,temp.ename '上级领导名',temp.`领导编号`,temp.`领导名称` FROM t_sanguo t LEFT JOIN (
SELECT t1.*,t2.eid '领导编号' , t2.ename '领导名称' FROM t_sanguo t1 LEFT JOIN t_sanguo t2 ON t1.manager_id=t2.eid
) temp ON t.manager_id=temp.eid-- 下面是采用自关联三张表的操作进行的查询的操作将自己作为三张独立的表进行的关联的查询的操作
SELECT
t1.eid ,t1.ename ,
t2.eid '上级领导编号' ,t2.ename '上级领导姓名',
t3.eid '上上级领导编号',t3.ename '上上级领导姓名'
FROM t_sanguo t1
LEFT JOIN t_sanguo t2 on t1.manager_id =t2.eid
LEFT JOIN t_sanguo t3 on t2.manager_id =t3.eid
15.7多表查询总结
外键约束
-
主表
-
从表
外键约束的创建的方式
-
直接在后面加上外键
-
采用修改表的方式进行创建外键约束
特点:
-
主表的数据可以随便加,不能随便删除
-
从表的数据可随便删除,不能随便添加
连接查询
-
内:join就是。两张表的交集。
-
外:左外和右外。
-
全:union可以合并左外和右外的连接的查询的结果
-
交叉:不用,笛卡尔积
自查询:
-
select的嵌套查询
-
子查询的结果作为一个值 = 的操作,多个值 in的操作。当作一个表,可以进行表的连接的查询的操作
关键字
-
all:全部满足
-
any和some只是有一个满足就是可以的
-
exists:如果查询的有结果就是可以的,否则就是false
自关联:
-
表必须起别名
16.子查询
嵌套多个具有子查询的小查询。返回的中间结果存在多种。
单行单列
单行多列
多行多列
多行多列
-- =================子查询
-- 查询年龄最大的员工的信息。包含员工全部信息
-- 单行单列可以直接采用=
SELECT MAX(age) FROM emp3;
SELECT * FROM emp3 WHERE age=(SELECT MAX(age) FROM emp3);
SELECT * FROM emp3 WHERE age in (SELECT MAX(age) FROM emp3);-- 查询研发部和销售部的员工的信息
SELECT * FROM emp3 WHERE dept_id in (SELECT deptno FROM dept WHERE name in ('研发部','销售部') );SELECT * FROM emp3 e INNER JOIN dept d on e.dept_id=d.deptno;
下面展示的是多表查询,设置了连个子查询然后进行了表连接。
17.IN关键字
只要是任意一个符合就是可以得。等价于得语句就是or
select from where c=result1 or c=result2 or c=result3-- 查询研发部和销售部员工的信息
SELECT * FROM emp3 WHERE dept_id IN (SELECT deptno FROM dept3 WHERE name='研发部' or name ='销售部');
18.exists关键字
和IN关键字是差不多的
其实就是给出一个让where查询条件成立的一个表达式语句
select from where exists 查询语句
-
返回至少存在一行数据得话就是可以 得返回得是true要是不成立得话就是不成立得。
-
exists后面得子查询中不反悔任何得数据。只能返回真和假,就是给where进行成立得。
-- 下面会进行全表得输出
SELECT * FROM emp3 WHERE EXISTS (SELECT * FROM emp3) -- 查询公司大于60岁得员工
SELECT * FROM emp3 WHERE age >60;
-- 下面就是采用exists进行得操作
SELECT * FROM emp3 e WHERE EXISTS ( SELECT * FROM emp3 WHERE e.age>60);-- 查询有所属部门得员工的信息
SELECT * FROM emp3 e WHERE EXISTS (SELECT * FROM dept3 d WHERE e.dept_id =d.deptno);-- 查询没有所属部门得员工的信息
SELECT * FROM emp3 e WHERE not EXISTS (SELECT * FROM dept3 d WHERE e.dept_id =d.deptno);
exists的查询的效率是比较高得。
19.MySQL常见的函数
别人写好的模板代码。
聚合函数
数学函数
日期函数
控制流函数
窗口函数
19.1聚合函数
前面学的就是count,sum。ave和max,min
现在有一个group_
-- 创建一个新的表
CREATE TABLE `emp4` (`id` int(11) NOT NULL AUTO_INCREMENT,`name` varchar(255) DEFAULT NULL,`salary` decimal(10,2) DEFAULT NULL,`dept_id` varchar(255) DEFAULT NULL,PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;-- 准备下面的测试数据
INSERT INTO `sys_test`.`emp4` (`id`, `name`, `salary`, `dept_id`) VALUES (1, '张三', 1200.00, '人事部');
INSERT INTO `sys_test`.`emp4` (`id`, `name`, `salary`, `dept_id`) VALUES (2, '李四', 1500.00, '财务部');
INSERT INTO `sys_test`.`emp4` (`id`, `name`, `salary`, `dept_id`) VALUES (3, '王五', 1600.00, '财务部');
INSERT INTO `sys_test`.`emp4` (`id`, `name`, `salary`, `dept_id`) VALUES (4, '赵六', 1700.00, '人事部');
INSERT INTO `sys_test`.`emp4` (`id`, `name`, `salary`, `dept_id`) VALUES (5, '陈二', 1500.00, '销售部');
INSERT INTO `sys_test`.`emp4` (`id`, `name`, `salary`, `dept_id`) VALUES (6, '张伞', 1600.00, '销售部');
INSERT INTO `sys_test`.`emp4` (`id`, `name`, `salary`, `dept_id`) VALUES (7, '招录', 1700.00, '销售部');
将所有的员工的名字合成一行
-- 聚合操作
-- 将所有的员工的名字合成一行-- 默认的是逗号分隔符
SELECT GROUP_CONCAT(name) FROM emp4;-- 指定分隔符
SELECT GROUP_CONCAT(name SEPARATOR '-') FROM emp4;-- 指定分组的方式
SELECT dept_id, GROUP_CONCAT(name SEPARATOR '-') FROM emp4 group by dept_id;-- 指定排序的规则
SELECT dept_id, GROUP_CONCAT(name ORDER BY salary SEPARATOR '-') FROM emp4 group by dept_id;
先按照部门的名称进行分组然后再进行拼接的操作
下面是指定排序表的规则的操作
19.2数学函数
-- ==============================数学函数=========================
-- 绝对值
SELECT ABS(-10);-- 往上取整 结果是2
SELECT CEIL(1.1);-- 往下取整 结果是1
SELECT floor(1.1);-- 返回列表的最大值
SELECT GREATEST(1,2,3);-- 返回列表的最小值
SELECT least(1,2,3);-- mod 取余数
SELECT MOD(5,2)-- INDEX
SELECT POWER(5,2)-- 随机数
-- 0-1之间
SELECT RAND();-- 返回0-100之间的
SELECT RAND()*100;-- 四舍五入
SELECT ROUND(3.56);
SELECT ROUND(3.46);-- 保留小数位数
SELECT ROUND(3.46,1);-- 直接取几位不四舍五入
SELECT TRUNCATE (3.1415926,3);
19.3字符串函数
-- ===========================字符串函数=======================
-- 返回字符串字符个数
SELECT char_length('hello') ;-- 注意一个汉字是一个字符
SELECT char_length('你好啊') ;-- length根据的是字节进行的计算
SELECT length('hello') ;-- 一个汉字3个字节。采用的是utf8编码导致的
SELECT length('你好啊') ;-- 字符串合并 没有分隔符
SELECT CONCAT('你好','啊')-- 字符串合并 有分隔符,第一个就是就是分隔符
SELECT CONCAT_WS('-','你好','啊')-- 返回字符串在列表中的位置 第一次出现的位置
-- 你好在后面字符中出现的位置 1
SELECT FIELD('你好','你好','啊','张伞')
-- 位置2
SELECT FIELD('啊','你好','啊','张伞')-- 去除左边的空格
SELECT ' 你好';
SELECT LTRIM(' 你好');-- 去除右边的空格
SELECT RTRIM('你好 ')-- 去除两侧的空格
SELECT trim(' 你好 ')-- 从字符串s中截取
-- 从第2个字符开始,截取的长度为3。从1开始的。
-- 结果:ell
SELECT MID('helloworld',2,3)-- 判断一个字符串在另外一个字符串中出现的位置
-- 从1开始的
SELECT POSITION('wo' in 'helloworld')-- 字符串替换
-- 替换的是所有符合规则的
SELECT REPLACE('helloworld','hello' ,'你好');-- 字符串反转
SELECT REVERSE('helloworld');-- ===========================字符串函数=======================
-- 返回字符串后几个字符 llo
SELECT RIGHT('hello',3);-- 比较两个字符串的大小
-- -1表示小于,挨个字符进行比较的,按照的是字典的顺序
SELECT STRCMP('hello','hi');-- 字符串截取
-- ell从第2个字符开始截取3个字符 ell
SELECT SUBSTR('hello' ,2 ,3);
SELECT SUBSTring('hello' ,2 ,3);-- 小写变大写
SELECT ucase('hello' );
SELECT upper('hello' );-- 大写变小写SELECT lcase('HELLO' );
SELECT LOWER('HELLO' );
19.4日期相关函数
-- ====================下面是日期相关的函数=================
-- 返回毫秒值 获取时间戳 从1970年开始的
SELECT UNIX_TIMESTAMP();-- 将日期字符串转换成毫秒值
SELECT UNIX_TIMESTAMP('2023-08-18 08:47:05');-- 将毫秒值转换成指定格式的日期
-- 必须按照指定的格式
SELECT FROM_UNIXTIME(1692319625,'%Y-%m-%d %H:%i:%s')
格式化日期的时候必须按照下面的格式进行编写
- 获取当前的日期
-- 2023-08-18
SELECT CURDATE();
SELECT CURRENT_DATE();-- 获取当前时分秒
-- 08:51:39
SELECT CURRENT_TIME();
SELECT CURTIME();-- 获取完整的日期
-- 2023-08-18 08:52:04
SELECT CURRENT_TIMESTAMP();-- 从日期字符串中获取年月日
-- 需要符合日期的规范 2023-08-18
SELECT DATE('2023-08-18 08:52:04')-- 日期之间的差值 31
SELECT DATEDIFF('2023-08-18','2023-07-18')
下面是可以加减的日期的参数
-- 时间之间的插值。查了多少秒 00:01:00
SELECT TIMEDIFF('08:52:04','08:51:04');-- 日期按照指定的格式化 2023-08-18 08:52:04
-- 能够保证转换出来的日期的长度是一样的
SELECT DATE_FORMAT('2023-8-18 8:52:4','%Y-%m-%d %H:%i:%s')-- 字符串换日期 2023-08-18 08:52:04
SELECT STR_TO_DATE('2023-8-18 8:52:4','%Y-%m-%d %H:%i:%s')-- STR_TO_DATE可以把英文的时间也转换出来-- 日期进行减法 日期减去2天
SELECT DATE_SUB('2023-08-18 08:52:04',INTERVAL 2 DAY)-- 日期加法 2023-08-20 08:52:04
SELECT DATE_ADD('2023-08-18 08:52:04',INTERVAL 2 DAY)
SELECT ADDDate('2023-08-18 08:52:04',INTERVAL 2 DAY)-- 从日期中获取时间
SELECT EXTRACT(HOUR FROM '2023-08-18 08:52:04')SELECT EXTRACT(YEAR FROM '2023-08-18 08:52:04')SELECT EXTRACT(MONTH FROM '2023-08-18 08:52:04')-- 获取最后一天 2023-08-31
SELECT LAST_DAY('2023-08-18 08:52:04')-- 获取指定年的哪一天是几号
SELECT MAKEDATE('2023',8);-- 获取年
SELECT YEAR('2023-08-18 08:52:04');-- 获取月
SELECT MONTH('2023-08-18 08:52:04');-- 天
SELECT SECOND('2023-08-18 08:52:04');-- 小时
SELECT HOUR('2023-08-18 08:52:04');-- 分钟
SELECT MINUTE('2023-08-18 08:52:04');-- 秒
SELECT SECOND('2023-08-18 08:52:04');-- 获取季度 1-4
SELECT QUARTER('2023-08-18 08:52:04');-- 月的名字 August
SELECT MONTHNAME('2023-08-18 08:52:04');-- 天的名字
SELECT DAYNAME('2023-08-18 08:52:04');-- 这个月中第几天 18
SELECT DAYOFMONTH('2023-08-18 08:52:04');-- 周中第几天 6
SELECT DAYOFWeek('2023-08-18 08:52:04');-- 年中多少天 230
SELECT DAYOFYear('2023-08-18 08:52:04');-- 本年的第几个周 33
SELECT WEEK('2023-08-18 08:52:04');
-- 1
SELECT WEEK('2023-01-01 00:00:00');-- 今天是周几 4+1
SELECT WEEKDAY('2023-08-18 08:52:04');-- 本年第几个星期
SELECT WEEKOFYEAR('2023-08-18 08:52:04');-- 年份及第几周 202333
SELECT YEARWEEK('2023-08-18 08:52:04');-- 当前的时间
SELECT NOW();