【python MySQL 笔记】MySQL 查询

【python MySQL 笔记】MySQL 查询

目录

1.数据准备和基本查询

1.1. 数据准备

1.2.基本查询

2. 条件查询

2.1. 比较运算符

2.2. 逻辑运算符

2.3. 模糊查询

2.4. 范围查询

2.5. 空判断

3. 排序

4. 聚合函数

5. 分组

6. 分页

7. 连接查询

8. 自关联

9. 子查询

小结


1.数据准备和基本查询

1.1. 数据准备

创建数据库、两个数据表,用于语句的验证学习。

-- 数据的准备
    -- 创建一个数据库
    create database python_test charset=utf8;

    -- 使用一个数据库
    use python_test;

    -- 显示使用的当前数据是哪个?
    select database();

    -- 创建一个数据表
    -- students表
    create table students(
        id int unsigned primary key auto_increment not null,
        name varchar(20) default '',
        age tinyint unsigned default 0,
        height decimal(5,2),
        gender enum('男','女','中性','保密') default '保密',
        cls_id int unsigned default 0,
        is_delete bit default 0
    );

    -- classes表
    create table classes (
        id int unsigned auto_increment primary key not null,
        name varchar(30) not null
    );

向数据表中插入数据:

-- 向students表中插入数据
insert into students values
(0,'小明',18,180.00,2,1,0),
(0,'小月月',18,180.00,2,2,1),
(0,'彭于晏',29,185.00,1,1,0),
(0,'刘德华',59,175.00,1,2,1),
(0,'黄蓉',38,160.00,2,1,0),
(0,'凤姐',28,150.00,4,2,1),
(0,'王祖贤',18,172.00,2,1,1),
(0,'周杰伦',36,NULL,1,1,0),
(0,'程坤',27,181.00,1,2,0),
(0,'刘亦菲',25,166.00,2,2,0),
(0,'金星',33,162.00,3,3,1),
(0,'静香',12,180.00,2,4,0),
(0,'郭靖',12,170.00,1,4,0),
(0,'周杰',34,176.00,2,5,0);

-- 向classes表中插入数据
insert into classes values (0, "python_01班"), (0, "python_02班"), (0, "python_03班");

1.2.基本查询

-- 基本查询--------------------------------------

	-- 查询所有字段
	-- select * from 表名;
	select * from students;
	select * from classes;
	select id, name from classes;

	-- 查询 【指定字段】
	-- select 列1,列2,... from 表名;
	select name, age from students;
	
	-- 使用 as 【给字段起别名】
	-- select 字段 as 名字.... from 表名;
	select name as 姓名, age as 年龄 from students;

	-- select 表名.字段 .... from 表名;  可用于有多个表的时候
	select students.name, students.age from students;

	
	-- 可以通过 as 【给表起别名】
	-- select 别名.字段 .... from 表名 as 别名;
	select students.name, students.age from students;
	select s.name, s.age from students as s;
	-- 注:起了别名后,用原表名会查询失败,如下:
	-- 失败:select students.name, students.age from students as s;


	-- 消除重复行,【去重】,相同的结果只显示一次
	-- distinct 字段
	-- select distinct 列1,... from 表名;
	select distinct gender from students;

2. 条件查询

使用where子句对表中的数据筛选,结果为true的行会出现在结果集中

  • 语法如下:select * from 表名 where 条件;

where后面支持多种运算符,进行条件的处理

  • 比较运算符
  • 逻辑运算符
  • 模糊查询
  • 范围查询
  • 空判断

2.1. 比较运算符

-- 比较运算符-------------
	-- select .... from 表名 where .....
	-- >
	-- 查询大于18岁的信息
	select * from students where age>18;
	select id,name,gender from students where age>18;

	-- <
	-- 查询小于18岁的信息
	select * from students where age<18;

	-- >=
	-- <=
	-- 查询小于或者等于18岁的信息
	select * from students where age<=18;

	-- =
	-- 查询年龄为18岁的所有学生的名字
	select * from students where age=18;

	-- != 或者 <> 不等于

2.2. 逻辑运算符

-- 逻辑运算符-------------
	-- 与【and】
	-- 18到28之间的所以学生信息
	select * from students where age>18 and age<28;
	-- 失败select * from students where age>18 and <28;


	-- 18岁以上的女性
	select * from students where age>18 and gender="女";
	select * from students where age>18 and gender=2;


	-- 或【or】
	-- 18以上或者身高查过180(包含)以上
	select * from students where age>18 or height>=180;


	-- 非【not】
	-- 不在 18岁以上的女性 这个范围内的信息
	-- select * from students where not age>18 and gender=2;
	select * from students where not (age>18 and gender=2);

	-- 年龄不是小于或者等于18 并且是女性
	select * from students where (not age<=18) and gender=2;

2.3. 模糊查询

-- 模糊查询----------------
	-- 【like】
	-- % 表示0个或者多个字符
	-- _ 表示1个字符
	
	-- 查询姓名中 以 "小" 开始的名字
	-- select name from students where name="小"; --只能查出name="小"的
	select name from students where name like "小%";

	-- 查询姓名中 包含 "小" 的所有名字
	select name from students where name like "%小%";

	-- 查询有2个字的名字(用两个下划线替代)
	select name from students where name like "__";

	-- 查询有3个字的名字
	select name from students where name like "___";

	-- 查询至少有2个字的名字
	select name from students where name like "__%";


	-- 【rlike】 正则表达式
	
	-- 查询以 周开始的姓名
	select name from students where name rlike "^周.*";

	-- 查询以 周开始、伦结尾的姓名
	select name from students where name rlike "^周.*伦$";

2.4. 范围查询

-- 范围查询-----------------
	-- 【in】(1, 3, 8)表示在一个非连续的范围内
	-- 查询 年龄为18、34的姓名
	select name,age from students where age=18 or age=34;
	select name,age from students where age=18 or age=34 or age=12;
	select name,age from students where age in (12, 18, 34);


	
	-- 【not in】 不非连续的范围之内
	-- 年龄不是 12、18、34岁之间的信息
	select name,age from students where age not in (12, 18, 34);


	-- 【 between ... and ... 】表示在一个连续的范围内
	-- 查询 年龄在18到34之间的的信息
	select name, age from students where age between 18 and 34;

	
	-- 【not between ... and ...】表示不在一个连续的范围内
	-- 查询 年龄不在在18到34之间的的信息
	select * from students where age not between 18 and 34;
	select * from students where not age between 18 and 34;
	-- 失败:select * from students where age not (between 18 and 34);

2.5. 空判断

-- null 空判断----------------------
		
	-- 注意:null与''是不同的
	-- 判空【 is null 】
	-- 查询身高为空的信息
	select * from students where height is null;
	select * from students where height is NULL;

	-- 判非空【 is not null 】
	select * from students where height is not null;

3. 排序

为了方便查看数据,可以对数据进行排序

语法select * from 表名 order by 列1 asc|desc [,列2 asc|desc,...]

说明

  • 将行数据按照列1进行排序,如果某些行列1的值相同时,则按照列2排序,以此类推
  • 默认按照列值从小到大排列(asc)
  • asc从小到大排列,即升序
  • desc从大到小排序,即降序
-- 【 order by 】 字段
-- 【 asc 】从小到大排列,即升序
-- 【 desc 】从大到小排序,即降序

-- 查询年龄在18到34岁之间的男性,按照年龄从小到到排序
-- 默认排序
select * from students where (age between 18 and 34) and gender=1;
-- 按照年龄排序
select * from students where (age between 18 and 34) and gender=1 order by age;
select * from students where (age between 18 and 34) and gender=1 order by age asc;


-- 查询年龄在18到34岁之间的女性,身高从高到矮排序
select * from students where (age between 18 and 34) and gender=2 order by height desc;


-- 【order by 多个字段】:第一个字段相同则按第二个字段排...以此类推

-- 查询年龄在18到34岁之间的女性,身高从高到矮排序, 如果身高相同的情况下按照年龄从小到大排序
select * from students where (age between 18 and 34) and gender=2 order by height desc,id desc;


-- 查询年龄在18到34岁之间的女性,身高从高到矮排序, 如果身高相同的情况下按照年龄从小到大排序,
-- 如果年龄也相同那么按照id从大到小排序
select * from students where (age between 18 and 34) and gender=2 order by height desc,age asc,id desc;


-- 按照年龄从小到大、身高从高到矮的排序
select * from students order by age asc, height desc;

4. 聚合函数

为了快速得到统计数据,经常会用到聚合函数:

  • 总数:count(*) 表示计算总行数,括号中写星与列名,结果是相同的
  • 最大值:max(列) 表示求此列的最大值
  • 最小值:min(列) 表示求此列的最小值
  • 求和:sum(列) 表示求此列的和
  • 平均值:avg(列) 表示求此列的平均值
  • 保留小数位数、四舍五入:round(表达式, 位数),如 round(123.234 , 1) 保留123.234的1位小数,并是四舍五入
-- 聚合函数-----------------------------------

	-- 总数
	-- 【count】
	-- 查询男性有多少人,女性有多少人
	select * from students where gender=1;  -- 查询gender=1
	select count(*) from students where gender=1;  -- gender-1总数
	select count(*) as 男性人数 from students where gender=1;
	select count(*) as 女性人数 from students where gender=2;


	-- 最大值
	-- 【max】
	-- 查询最大的年龄
	select age from students;
	select max(age) from students;

	-- 查询女性的最高 身高
	select max(height) from students where gender=2;

	-- 最小值
	-- 【min】

	
	-- 求和
	-- 【sum】
	-- 计算所有人的年龄总和
	select sum(age) from students;

	
	-- 平均值
	-- 【avg】
	-- 计算平均年龄
	select avg(age) from students;


	-- 计算平均年龄 sum(age)/count(*)  注:select后面可以放表达式
	select sum(age)/count(*) from students;


	-- 保留小数位数、四舍五入
	-- 【round】  
	-- round(123.234 , 1)    保留1位小数
	
	-- 计算所有人的平均年龄,保留2位小数
	select round(sum(age)/count(*), 2) from students;
	-- 保留三位小数
	select round(sum(age)/count(*), 3) from students;

	-- 计算男性的平均身高 保留2位小数
	select round(avg(height), 2) from students where gender=1;
	-- select name, round(avg(height), 2) from students where gender=1;

	

注:以上最后一句执行失败,通俗的说聚合函数不能和查询其他字段一起用。想要达到这样的目的,就要使用分组

5. 分组

分组将查询结果按照字段(1个或多个)进行分组,字段值相同的为一组。

GROUP BY 属性名 [HAVING 条件表达式] [WITH ROLLUP]

  1. 单独使用,只显示出每组的第一条记录(毫无意义);
  2. 与 GROUP_CONCAT()函数一起使用;
  3. 与聚合函数一起使用;
  4. 与 HAVING 一起使用(限制输出的结果);
  5. 与 WITH ROLLUP 一起使用(最后加入一个总和行);
  6. 注:group by可用于单个字段分组,也可用于多个字段分组;

select ... from 表名 group by ... ;

分组的一些特点:把原来的数据先分成组,条件再从组里面取数据。这样可以按分组统计分组字段的人数。如按性别分组,可统计每种性别的人数。

结合以下语句理解:

单独使用:

-- 【group by 单独使用】---------------
	-- 按照性别分组,查询所有的性别(只能显示所有的性别,不显示性别相应的数据)
	-- 失败 select * from students group by gender;
	-- 失败 select name from students group by gender;
	select gender from students group by gender;
	查询结果:
	+--------+
	| gender |
	+--------+
	| 男     |
	| 女     |
	| 中性   |
	| 保密   |
	+--------+

group by + group_concat():

  1. group_concat(字段名)可以作为一个输出字段来使用,
  2. 表示分组之后,根据分组结果,使用group_concat()来放置每一组的某字段的值的集合
  3. group_concat() 的参数其实不限于字段名,还可以是字符串
-- 【group by + group_concat(...)】---------------
-- 按照性别分组,查询每种性别都有谁(名字)
select gender,group_concat(name) from students group by gender;
+--------+-----------------------------------------------------------+
| gender | group_concat(name)                                        |
+--------+-----------------------------------------------------------+
| 男     | 彭于晏,刘德华,周杰伦,程坤,郭靖                              |
| 女     | 小明,小月月,黄蓉,王祖贤,刘亦菲,静香,周杰                     |
| 中性   | 金星                                                      |
| 保密   | 凤姐                                                      |
+--------+-----------------------------------------------------------+

-- 查询男性中的姓名(有谁是男性)
select gender,group_concat(name) from students where gender=1 group by gender;
-- 查询男性中的姓名、年龄、id
select gender,group_concat(name, age, id) from students where gender="男" group by gender;
-- 查询男性中的姓名、年龄、id,并优化显示(!group_concat可加字符串)
select gender,group_concat(name, "_", age, " ", id) from students where gender=1 group by gender;

+--------+-----------------------------------------------------------------------+
| gender | group_concat(name, "_", age, " ", id)                                 |
+--------+-----------------------------------------------------------------------+
| 男     | 彭于晏_29 3,刘德华_59 4,周杰伦_36 8,程坤_27 9,郭靖_12 13                 |
+--------+-----------------------------------------------------------------------+

以上,通俗的:select 想要的查询 from 数据表名 where 条件 group by 字段名;

group by + 集合函数:

通过group_concat()的启发,我们既然可以统计出每个分组的某字段的值的集合,那么我们也可以通过集合函数来对这个值的集合做一些操作。

-- 【group by + 集合函数】------

-- !计算每种性别中的人数:【注】按性别分组,再到每个分组里查。count(*)是对分组的结果计算个数!!
select gender,count(*) from students group by gender;
+--------+----------+
| gender | count(*) |
+--------+----------+
| 男     |        5 |
| 女     |        7 |
| 中性   |        1 |
| 保密   |        1 |
+--------+----------+

-- 计算男性的人数
select gender,count(*) from students where gender=1 group by gender;


-- 分别统计各性别的人的年龄平均值
select gender,avg(age) from students group by gender;
+--------+----------+
| gender | avg(age) |
+--------+----------+
| 男     |  32.6000 |
| 女     |  23.2857 |
| 中性   |  33.0000 |
| 保密   |  28.0000 |
+--------+----------+


-- 分别统计各性别的人的个数
select gender,count(*) from students group by gender;
+--------+----------+
| gender | count(*) |
+--------+----------+
| 男     |        5 |
| 女     |        7 |
| 中性   |        1 |
| 保密   |        1 |
+--------+----------+

group by + having:

  1. having 条件表达式:用来分组查询后指定一些条件来输出查询结果,即对分组进行条件判断;
  2. having作用和where一样,但having只能用于group by;
  3. where 是对原始表进行条件判断,而having是对查出来的结果进行条件判断
-- 4【group by + having】
	-- 查询平均年龄超过30岁的性别,以及姓名 having avg(age) > 30
	select gender, group_concat(name),avg(age) from students group by gender having avg(age)>30;
	+--------+---------------------------------------------+
	| gender | group_concat(name)                          |
	+--------+---------------------------------------------+
	| 男     | 彭于晏,刘德华,周杰伦,程坤,郭靖                |
	| 中性   | 金星                                         |
	+--------+---------------------------------------------+
	
	-- 查询每种性别中的人数多于2个的信息
	select gender, group_concat(name) from students group by gender having count(*)>2;
	+--------+-----------------------------------------------------------+
	| gender | group_concat(name)                                        |
	+--------+-----------------------------------------------------------+
	| 男     | 彭于晏,刘德华,周杰伦,程坤,郭靖                               |
	| 女     | 小明,小月月,黄蓉,王祖贤,刘亦菲,静香,周杰                     |
	+--------+-----------------------------------------------------------+

group by + with rollup

with rollup的作用是:在最后新增一行,来记录当前列里所有记录的总和。

-- 查询各性别的人数
select gender,count(*) from students group by gender with rollup;
+--------+----------+
| gender | count(*) |
+--------+----------+
| 男     |        5 |
| 女     |        7 |
| 中性   |        1 |
| 保密   |        1 |
| NULL   |       14 |
+--------+----------+

-- 查询各性别的年龄数据,最后一行记录所有查到的数据
select gender,group_concat(age) from students group by gender with rollup;
+--------+-------------------------------------------+
| gender | group_concat(age)                         |
+--------+-------------------------------------------+
| 男     | 29,59,36,27,12                            |
| 女     | 18,18,38,18,25,12,34                      |
| 中性   | 33                                        |
| 保密   | 28                                        |
| NULL   | 29,59,36,27,12,18,18,38,18,25,12,34,33,28 |
+--------+-------------------------------------------+

6. 分页

当数据量过大时,在一页中查看数据是一件非常麻烦的事情,所以应适当对查询结果进行分页。

语法:select * from 表名 limit start, count;

  • 从start开始,获取count条数据

如:select * from students where gender="男" limit 0,3;   ,从0开始,获取3行男性信息。

注:对第N页分页时的规律, limit (第N页-1)*每个的个数, 每页的个数;

-- 分页--------------------------------------------
	-- limit start, count

	-- 限制查询出来的数据个数 为2个
	select * from students where gender=1 limit 2;

	-- 查询前5个数据
	select * from students limit 0, 5;

	-- 查询id6-10(包含)的书序
	select * from students limit 5, 5;

	
	-- 每页显示2个,第1个页面
	select * from students limit 0,2;

	-- 每页显示2个,第2个页面
	select * from students limit 2,2;

	-- 每页显示2个,第3个页面
	select * from students limit 4,2;

	-- 每页显示2个,第4个页面
	select * from students limit 6,2; -- -----> limit (第N页-1)*每个的个数, 每页的个数;

	-- 每页显示2个,显示第6页的信息, 按照年龄从小到大排序
	-- 失败select * from students limit 2*(6-1),2;
	-- 失败select * from students limit 10,2 order by age asc;  -- limit应该放在 order by 后面
	select * from students order by age asc limit 10,2;

	-- 查询女性的信息,身高从高到低排序,只显示两个
	select * from students where gender=2 order by height desc limit 0,2;

7. 连接查询

连接查询是将两个或两个以上的表按照某个条件连接起来,从中选取需要的数据;

即当查询结果的列来源于多张表时,需要将多张表连接成一个大的数据集,再选择合适的列返回。

mysql支持三种类型的连接查询:内连接查询、右连接查询、左连接查询。后两种可称为连接查询。

1. 内连接查询:查询的结果为两个表匹配到的数据;内连接查询是一种最常用的连接查询。内连接查询可以查询两个或者两个以上的表;即 inner 查询以 表名1.属性名1=表名2.属性名2 为前提,且以此为前提显示

2. 右连接查询:查询的结果为两个表匹配到的数据、右表特有的数据,对于左表中不存在的数据使用null填充;

3. 左连接查询:查询的结果为两个表匹配到的数据、左表特有的数据,对于右表中不存在的数据使用null填充;通俗的说,以左表为基准进行查询,取不出的默认为null。

语法SELECT 属性名列表 FROM 表名 1 INNER|LEFT|RIGHT JOIN 表名 2 ON 表名1.属性名 1=表名2.属性名 2;

即:select * from 表1 inner或left或right join 表2 on 表1.列 = 表2.列;

SELECT 属性名列表 FROM 表名 1 INNER|LEFT|RIGHT JOIN 表名 2 ON 表名1.属性名 1=表名2.属性名 2;

查询语句笔记:

-- 连接查询--------------------------------------
	
	-- 【inner join ... on】-----------

	-- select ... from 表A inner join 表B;(没有 on 会显示所有表A和表B的组合结果,没什么实际意义)
	select * from students inner join classes;

	-- 查询 在classes表有对应班级的学生以及班级信息
	select * from students inner join classes on students.cls_id=classes.id;
	+----+-----------+------+--------+--------+--------+-----------+----+--------------+
	| id | name      | age  | height | gender | cls_id | is_delete | id | name         |
	+----+-----------+------+--------+--------+--------+-----------+----+--------------+
	|  1 | 小明      |   18 | 180.00 | 女     |      1 |           |  1 | python_01班  |
	|  2 | 小月月    |   18 | 180.00 | 女     |      2 |          |  2 | python_02班   |
	|  3 | 彭于晏    |   29 | 185.00 | 男     |      1 |           |  1 | python_01班  |
	|  4 | 刘德华    |   59 | 175.00 | 男     |      2 |          |  2 | python_02班  |
	|  5 | 黄蓉      |   38 | 160.00 | 女     |      1 |           |  1 | python_01班  |
	|  6 | 凤姐      |   28 | 150.00 | 保密   |      2 |          |  2 | python_02班  |
	|  7 | 王祖贤    |   18 | 172.00 | 女     |      1 |          |  1 | python_01班  |
	|  8 | 周杰伦    |   36 |   NULL | 男     |      1 |           |  1 | python_01班  |
	|  9 | 程坤      |   27 | 181.00 | 男     |      2 |           |  2 | python_02班  |
	| 10 | 刘亦菲    |   25 | 166.00 | 女     |      2 |           |  2 | python_02班  |
	| 11 | 金星      |   33 | 162.00 | 中性   |      3 |          |  3 | python_03班  |
	+----+-----------+------+--------+--------+--------+-----------+----+--------------+

	-- 按照要求显示姓名、班级
	select students.name, classes.name from students inner join classes on students.cls_id=classes.id;
	-- 给数据表起别名
	select s.name, c.name from students as s inner join classes as c on s.cls_id=c.id;
	+-----------+--------------+
	| name      | name         |
	+-----------+--------------+
	| 小明      | python_01班  |
	| 小月月    | python_02班  |
	| 彭于晏    | python_01班  |
	| 刘德华    | python_02班  |
	| 黄蓉      | python_01班  |
	| 凤姐      | python_02班  |
	| 王祖贤    | python_01班  |
	| 周杰伦    | python_01班  |
	| 程坤      | python_02班  |
	| 刘亦菲    | python_02班  |
	| 金星      | python_03班  |
	+-----------+--------------+
	
	-- 查询 在classes表有对应班级的学生以及班级信息,显示学生的所有信息,只显示班级名称
	select students.*, classes.name from students inner join classes on students.cls_id=classes.id;
	select s.*, c.name from students as s inner join classes as c on s.cls_id=c.id;
	
	-- 在以上的查询中,将班级姓名显示在第1列
	select c.name, s.* from students as s inner join classes as c on s.cls_id=c.id;

	-- 查询 在classes表有对应班级的学生以及班级信息, 按照班级进行排序
	-- select c.xxx s.xxx from student as s inner join clssses as c on .... order by ....;
	select c.name, s.* from students as s inner join classes as c on s.cls_id=c.id order by c.name;
	
	-- 当时同一个班级的时候,按照学生的id进行从小到大排序
	select c.name, s.* from students as s inner join classes as c on s.cls_id=c.id order by c.name,s.id;
	+--------------+----+-----------+------+--------+--------+--------+-----------+
	| name         | id | name      | age  | height | gender | cls_id | is_delete |
	+--------------+----+-----------+------+--------+--------+--------+-----------+
	| python_01班  |  1 | 小明      |   18 | 180.00 | 女     |      1 |           |
	| python_01班  |  3 | 彭于晏    |   29 | 185.00 | 男     |      1 |           |
	| python_01班  |  5 | 黄蓉      |   38 | 160.00 | 女     |      1 |           |
	| python_01班  |  7 | 王祖贤    |   18 | 172.00 | 女     |      1 |          |
	| python_01班  |  8 | 周杰伦    |   36 |   NULL | 男     |      1 |           |
	| python_02班  |  2 | 小月月    |   18 | 180.00 | 女     |      2 |          |
	| python_02班  |  4 | 刘德华    |   59 | 175.00 | 男     |      2 |          |
	| python_02班  |  6 | 凤姐      |   28 | 150.00 | 保密   |      2 |          |
	| python_02班  |  9 | 程坤      |   27 | 181.00 | 男     |      2 |           |
	| python_02班  | 10 | 刘亦菲    |   25 | 166.00 | 女     |      2 |           |
	| python_03班  | 11 | 金星      |   33 | 162.00 | 中性   |      3 |          |
	+--------------+----+-----------+------+--------+--------+--------+-----------+

	
	-- 【left join】--------------
	-- 查询每位学生对应的班级信息
	select * from students as s left join classes as c on s.cls_id=c.id;
	+----+-----------+------+--------+--------+--------+-----------+------+--------------+
	| id | name      | age  | height | gender | cls_id | is_delete | id   | name         |
	+----+-----------+------+--------+--------+--------+-----------+------+--------------+
	|  1 | 小明      |   18 | 180.00 | 女     |      1 |           |    1 | python_01班  |
	|  3 | 彭于晏    |   29 | 185.00 | 男     |      1 |           |    1 | python_01班  |
	|  5 | 黄蓉      |   38 | 160.00 | 女     |      1 |           |    1 | python_01班  |
	|  7 | 王祖贤    |   18 | 172.00 | 女     |      1 |          |    1 | python_01班  |
	|  8 | 周杰伦    |   36 |   NULL | 男     |      1 |           |    1 | python_01班  |
	|  2 | 小月月    |   18 | 180.00 | 女     |      2 |          |    2 | python_02班  |
	|  4 | 刘德华    |   59 | 175.00 | 男     |      2 |          |    2 | python_02班  |
	|  6 | 凤姐      |   28 | 150.00 | 保密   |      2 |          |    2 | python_02班  |
	|  9 | 程坤      |   27 | 181.00 | 男     |      2 |           |    2 | python_02班  |
	| 10 | 刘亦菲    |   25 | 166.00 | 女     |      2 |           |    2 | python_02班  |
	| 11 | 金星      |   33 | 162.00 | 中性   |      3 |          |    3 | python_03班  |
	| 12 | 静香      |   12 | 180.00 | 女     |      4 |           | NULL | NULL         |
	| 13 | 郭靖      |   12 | 170.00 | 男     |      4 |           | NULL | NULL         |
	| 14 | 周杰      |   34 | 176.00 | 女     |      5 |           | NULL | NULL         |
	+----+-----------+------+--------+--------+--------+-----------+------+--------------+
	-- 以上的查询结果可以当作一个表来看,故可以用 having 来对结果过滤,如下查询语句。(此处where也行)
	
	-- 查询 在classes表中没有对应班级信息的学生
	-- select ... from xxx as s left join xxx as c on..... having .....
	-- select ... from xxx as s left join xxx as c on..... where .....
	select * from students as s left join classes as c on s.cls_id=c.id having c.id is null;
	select * from students as s left join classes as c on s.cls_id=c.id where c.id is null;
	+----+--------+------+--------+--------+--------+-----------+------+------+
	| id | name   | age  | height | gender | cls_id | is_delete | id   | name |
	+----+--------+------+--------+--------+--------+-----------+------+------+
	| 12 | 静香   |   12 | 180.00 | 女     |      4 |           | NULL | NULL |
	| 13 | 郭靖   |   12 | 170.00 | 男     |      4 |           | NULL | NULL |
	| 14 | 周杰   |   34 | 176.00 | 女     |      5 |           | NULL | NULL |
	+----+--------+------+--------+--------+--------+-----------+------+------+

	-- 【right join】 on ------------
	-- 将数据表名字互换位置,右连接就变左连接,用left join完成即可

8. 自关联

自关联:表中的某一列,关联了这个表中的另外一列,但是它们的业务逻辑含义是不一样的。

地区的行政管理、公司部门的上下级部门行政级别管理等会应用到。如下实例:

设计省信息的表结构provinces

  • id
  • ptitle

设计市信息的表结构citys

  • id
  • ctitle
  • proid

citys表的proid表示城市所属的省,对应着provinces表的id值

问题:能不能将两个表合成一张表呢?

思考:观察两张表发现,citys表比provinces表多一个列proid,其它列的类型都是一样的。

意义:存储的都是地区信息,而且每种信息的数据量有限,没必要增加一个新表,或者将来还要存储区、乡镇信息,都增加新表的开销太大。

答案:定义表areas,结构如下

  • id

  • atitle

  • pid

说明:

  • 因为省没有所属的省份,所以可以填写为null
  • 城市所属的省份pid,填写省所对应的编号id
  • 这就是自关联,表中的某一列,关联了这个表中的另外一列,但是它们的业务逻辑含义是不一样的,城市信息的pid引用的是省信息的id
  • 在这个表中,结构不变,可以添加区县、乡镇街道、村社区等信息

SQL语句

创建areas表的语句:

create table areas(
    aid int primary key,
    atitle varchar(20),
    pid int
);

在终端中,cd 至 areas.sql; 文件所在的目录,登录mysql数据库,use相应的数据库,从sql文件中导入数据

source areas.sql;

注:areas.sql中导入的部分数据如下(数据并非最新):

INSERT INTO `areas` (aid, pid, atitle) VALUES (11, NULL, '北京');
INSERT INTO `areas` (aid, pid, atitle) VALUES (110100, 11, '北京市辖');
INSERT INTO `areas` (aid, pid, atitle) VALUES (110101, 1101, '东城区');
INSERT INTO `areas` (aid, pid, atitle) VALUES (110102, 1101, '西城区');
INSERT INTO `areas` (aid, pid, atitle) VALUES (110103, 1101, '崇文区');
INSERT INTO `areas` (aid, pid, atitle) VALUES (110104, 1101, '宣武区');
INSERT INTO `areas` (aid, pid, atitle) VALUES (110105, 1101, '朝阳区');
INSERT INTO `areas` (aid, pid, atitle) VALUES (110106, 1101, '丰台区');
INSERT INTO `areas` (aid, pid, atitle) VALUES (110107, 1101, '石景山区');
INSERT INTO `areas` (aid, pid, atitle) VALUES (110108, 1101, '海淀区');
INSERT INTO `areas` (aid, pid, atitle) VALUES (110109, 1101, '门头沟区');
INSERT INTO `areas` (aid, pid, atitle) VALUES (110111, 1101, '房山区');
INSERT INTO `areas` (aid, pid, atitle) VALUES (110112, 1101, '通州区');
INSERT INTO `areas` (aid, pid, atitle) VALUES (110113, 1101, '顺义区');
INSERT INTO `areas` (aid, pid, atitle) VALUES (110114, 1101, '昌平区');
INSERT INTO `areas` (aid, pid, atitle) VALUES (1102, 11, '北京县辖');
INSERT INTO `areas` (aid, pid, atitle) VALUES (110224, 1102, '大兴县');
INSERT INTO `areas` (aid, pid, atitle) VALUES (110226, 1102, '平谷县');
INSERT INTO `areas` (aid, pid, atitle) VALUES (110227, 1102, '怀柔县');
INSERT INTO `areas` (aid, pid, atitle) VALUES (110228, 1102, '密云县');
INSERT INTO `areas` (aid, pid, atitle) VALUES (110229, 1102, '延庆县');
INSERT INTO `areas` (aid, pid, atitle) VALUES (12, NULL, '天津');
INSERT INTO `areas` (aid, pid, atitle) VALUES (1201, 12, '天津市辖');
INSERT INTO `areas` (aid, pid, atitle) VALUES (120101, 1201, '和平区');
INSERT INTO `areas` (aid, pid, atitle) VALUES (120102, 1201, '河东区');
INSERT INTO `areas` (aid, pid, atitle) VALUES (120103, 1201, '河西区');
INSERT INTO `areas` (aid, pid, atitle) VALUES (120104, 1201, '南开区');
-- ...

基于以上表,自关联查询笔记如下:

-- 自关联-----------------------------------------

	-- 查询所有省份
	select * from areas where pid is null;

	-- 查询出山东省有哪些地级市:
	-- 1.分两步
	select aid from areas where atitle="山东"  -- --查询山东的id: 得aid为37
	select * from areas where pid=37;
	
	
	-- 2.一步到位:一个表当两个表用,用内连接查询。用having过滤
	select * from areas as province inner join areas as city on city.pid=province.aid having province.atitle="山东";
		
	select province.atitle, city.atitle from areas as province inner join areas as city on city.pid=province.aid having province.atitle="山东";

		
	-- 查询出青岛市有哪些县城
	select province.atitle, city.atitle from areas as province inner join areas as city on city.pid=province.aid having province.atitle="青岛";
		
	select * from areas where pid=(select aid from areas where atitle="青岛");

9. 子查询

概念

在一个 select 语句中,嵌入了另外一个 select 语句, 那么被嵌入的 select 语句称之为子查询语句。主要查询的对象,第一条 select 语句为主查询。

 

主查询和子查询的关系:

  • 子查询是嵌入到主查询中
  • 子查询是辅助主查询的,要么充当条件,要么充当数据源
  • 子查询是可以独立存在的语句,是一条完整的 select 语句

子查询分类:

  • 标量子查询: 子查询返回的结果是一个数据(一行一列)
  • 列子查询: 返回的结果是一列(一列多行)
  • 行子查询: 返回的结果是一行(一行多列)

子查询中特定关键字使用:

  • in 范围
    • 格式: 主查询 where 条件 in (列子查询)
-- 子查询---------------------------------------
	-- 标量子查询: 子查询返回的结果是一个数据(一行一列)
	
	-- 查询出高于平均身高的信息(其中子查询中返回最高的身高)
	select * from students where height = (select max(height) from students);

	-- 列级子查询:
	-- 查询 在classes表有对应班级的学生的信息(其中子查询中返回一列班级id)
	select * from students where cls_id in (select id from classes);
	
	-- 行级子查询
	-- 需求: 查找班级年龄最大,身高最高的学生
	-- 行元素: 将多个字段合成一个行元素,在行级子查询中会使用到行元素
	select * from students where (height,age) = (select max(height),max(age) from students);

小结:

查询的完整格式 :

SELECT select_expr [,select_expr,...] [      
      FROM tb_name
      [WHERE 条件判断]
      [GROUP BY {col_name | postion} [ASC | DESC], ...] 
      [HAVING WHERE 条件判断]
      [ORDER BY {col_name|expr|postion} [ASC | DESC], ...]
      [ LIMIT {[offset,]rowcount | row_count OFFSET offset}]
]

完整的select语句

select distinct *
from 表名
where ....
group by ... having ...
order by ...
limit start,count

执行顺序

  • from 表名
  • where ....
  • group by ...
  • select distinct *
  • having ...
  • order by ...
  • limit start,count

在实际使用中,只是语句中某些部分的组合,而不是全部。

-------部分SQL数据/例子来自课件--------

------end--------

发布了50 篇原创文章 · 获赞 10 · 访问量 6611

猜你喜欢

转载自blog.csdn.net/qq_23996069/article/details/104320360