数据库--查询语句

查询语句

mysql中要学习的知识:多表关系,查询语句,索引

添加数据补充

将一个查询结果插入到另一张表中

create table student(name char(10), gender int);
insert into student values('nalituo', 1);
insert into student values('sasigi', 0);

create table student_man(name char(10), gender int);
# 快速将student表中性别为1的记录插入student_man表中
insert into student_man select * from student where gender = 1;

所有select关键字

select [distinct] * from table_name
	where
	group by
	having
	order by
	limit a,b


必须存在的 select
* 可以换成任意一个或者多个字段,可以重复,但是*必须写最前面
# 注意:关键字的顺序是固定的不能随意变化
# 注意:执行顺序distinct函数在having后面,其余从select到limit都和定义顺序相同

简单查询

  1. *表示通配符,显示所有字段

  2. 可以指定任意个字段名

  3. 可以对字段的数据进行四则运算

  4. 聚合函数,如下

取别名

  • 当字段名太长获取时不容易理解时,可以使用as来取别名,也可以不写as,直接空格加别名

    举例(下面查询的都是在这张表的基础上):where 条件

# 数据创建
create table stu(
	id int primary key auto_increment,
	name char(10),
    math float,
    english float
    );
insert into stu values(null,"赵云",90,30);
insert into stu values(null,"小乔",90,60);
insert into stu values(null,"小乔",90,60);
insert into stu values(null,"大乔",10,70);
insert into stu values(null,"李清照",100,100);
insert into stu values(null,"铁拐李",20,55);
insert into stu values(null,"小李子",20,55);

# 查看所有数据
select * from stu;
# 查看英语成绩
select english from stu;
# 查看每个人的总分
select english+math as 总分 from stu;
# 为每个人的数学都减10分
select math-10 数学 from stu;
# 不需要加引号,包括中文

1.where

select * from table_name
where 后接
1.比较运算符  > < >= <= = !=
2.成员运算符  in   not in  后面接一个set
3.逻辑运算符  and or not
4.模糊查询	like 
    % 表示0-任意个数的任意字符
    _ 表示1个任意字符
    %李%	表示查询所有带有李字的记录
5.between and 两者之间 两者都能取到值
6.is null 是否为空
7.exists 子查询语句

# 注意:int类型,查询的时候加上''也可以查到

举例:

# 查询姓大的,数学小于80分,并且英语大于20分的人的数学成绩
select name,math from stu where name like '大%' and math < 80 and english > 20;

# 查询英语及格的人的平均分
select name, (english+math)/2 as '平均分' from stu where english >= 60;

2.distinct 去除重复记录

# 仅在查询结果中所有字段全部相同时,才算重复的记录
select distinct * from stu;

# 名字相同就重复
select distinct name from stu;

3.group by

  • 分组,即将一个整体按照某个特征或依据来分为不同的部分

为什么要分组,分组是为了统计,例如统计男性有几个,女性有几个

数据准备:

create table emp(
	id int primary key auto_increment,
	name char(10),
	sex char(10),
	dept char(10),
	job char(10),
	salary float
	);
insert into emp values
(1,"刘备","男","市场","总监",5800),
(2,"张飞","男","市场","员工",3000),
(3,"关羽","男","市场","员工",4000),
(4,"孙权","男","行政","总监",6000),
(5,"周瑜","男","行政","员工",5000),
(6,"小乔","女","行政","员工",4000),
(7,"曹操","男","财务","总监",10000),
(8,"司马懿","男","财务","员工",6000);

# 语法:
select xxx from table_name group by 字段名;


# 需求:按照性别进行分组
select * from emp group by sex;
# 这样做只会显示该分组的第一行数据,这是因为emp有很多行,而分组聚合后的sex只有两行,两者的行数不匹配,逻辑是错误的。


# mysql 5.6下,查询的结果是name仅显示为该分组的第一个
# mysql 5.7以上则会直接报错,5.6也可以手动开启这个功能
# 把 ONLY_FULL_GROUP_BY 添加到服务器的配置文件中

统计函数

  • 也称之为聚合函数
  • 将一堆数据经过计算得出一个结果
  • sum avg count max min
  • 可以用在,字段的位置 ,或是分组的后面
求和:sum(字段名)
平均数  avg(字段名)
最大值  max(字段名)
最小值  min(字段名)
个数    count(字段名)    # 字段名称可以使用*代替,因为如果只查一个字段,那么当该字段为空时,是不计数的
 
# 例如:查找所有人的工资总和
select sum(salary) from emp;
  
# 例如:查询所有人的平均工资
select avg(salary) from emp;

# 例如:查询工资最高的人的姓名
select name,max(salary) from emp;
# 不是想要的效果,因为默认显示的是第一个name,因为name有很多行,而max(salary)只有一行

select name from emp where salary = max(salary);
# 报错,原因:伪代码
def where(条件):
    for line in file:
        if salary = max(salary) 
# 分析  where 读取满足条件的一行  ,max()先要拿到所有数据 才能求最大值。
# 但这里由于读取没有完成所有无法求出最大值
# 结论  where 后面不能使用聚合函数 

分组+统计

# 需求 查询每个性别有几个人
select sex, count(*) from emp group by sex;

# 需求:查询每个性别有几个人,并且显示名字
select name,sex,count(*) from emp group by sex;
# 报错

# 我们可以用group_concat 将分组之外的字段 做一个拼接 ,但是这是没有意义
# 如果要查询某个性别下的所有信息,直接使用where即可
# 结论,只有出现在了group by 后面得字段才能出现在select的后面

4.having

  • 用于过滤,但是与where不同的是,having使用在分组之后

案例:

# 求出平均工资大于5000的部门信息
select dept,avg(salary) from emp group by dept having avg(salary) > 5000;

# 查询部门人数少于3的部门名称 人员名称 人员个数
select dept, group_concat(name), count(*) from emp group by dept having count(*) < 3;

5.order by

  • 根据某个字段排序
# 语法
select * from table_name order by 字段名称;
# 默认升序,使用desc降序,asc升序

# 改为降序
select * from table_name order by 字段名称 desc;

# 多字段,先按照第一个排序,第一个相同,再按照第二个
select * from table_name order by 字段名称1 desc, 字段名称2 asc;

# 案例:工资升序,id降序
select * from emp order by salary asc, id desc;

6.limit

  • 用于限制要显示的记录数量
# 语法1
select * from table_name limit 个数;
# 语法2
select * from table_name limit 起始位置,个数;
# 语法3
select * from table_name limit 个数 offset 过滤个数;

# 案例:查询前三条
select * from emp limit 3;

# 从第3条开始,查询3条
select * from emp limit 2, 3;

# 从第4条开始,查询2条
select * from emp limit 2 offset 3;

# 注意:起始位置,从0开始
# 经典的使用场景:分页显示
1.每一页显示的条数 a = 3
2.明确当前页数 b = 2
3.计算起始位置 c = (b-1) * a

select * from emp limit 0,3;
select * from emp limit 3,3;
select * from emp limit 6,3;

# django中会提供一个分页功能,但是它是先查询所有数据,丢到列表中,再取出数据,这样如果数据量太大可能会有问题

子查询

将一条语句的结果作为另一条语句的条件或者是数据来源

当我们一次性查不到想要的数据时就需要使用子查询

in 关键字子查询

当内层查询(括号内的)结果会有多个结果时,不能使用=必须使用in,另外in查询只能包含一个字段,也就是一列数据

需求:找出平均年龄大于25的部门名称

准备数据:

drop table if exists emp;
create table emp (id int primary key ,name char(10),sex char,age int,dept_id int,job char(10),salary double);

insert into emp values
(1,"刘备","男",26,1,"总监",5800),
(2,"张飞","男",24,1,"员工",3000),
(3,"关羽","男",30,1,"员工",4000),
(4,"孙权","男",25,2,"总监",6000),
(5,"周瑜","男",22,2,"员工",5000),
(6,"小乔","女",31,2,"员工",4000),
(7,"曹操","男",19,3,"总监",10000),
(8,"司马懿","男",24,3,"员工",6000);

create table dept(id int primary key,name char(10));
insert into dept values(1,"市场"),(2,"行政"),(3,"财务");
# 1. 查询出平均年龄大于25的部门编号
select dept_id from emp group by dept_id having avg(age) > 25;

#2. 根据编号查询部门的名称
select * from dept where id in (1, 2);

# 子查询合并
select * from dept where id in (select  dept_id from emp  group by  dept_id  having avg(age) > 25);

子查询的思路:
1.要分析 查到最终的数据 到底有哪些步骤 
2.根据步骤写出对应的sql语句
3.把上一个步骤的sql语句丢到下一个sql语句中作为条件 

# 注意,如果用子查询,那么内部的语句查询的字段必须指定,而不能为*,否则会报错,因为外部得到的结果会乱掉

exist关键字子查询

  • 当内层查询有结果时,外层才会执行
# 案例
select * from dept where exists (select * from dept where id = 1);

# 由于内层查询产生了结果,所以执行了外层查询dept的所有数据

多表查询

笛卡尔积查询

# 案例:
select * from table1,table2,...

# 笛卡尔积查询在数据关联关系错误时,结果会出现大量的错误数据,
# 这时我们需要添加过滤条件,从表外键值等于主表的主键值
select * from emp, dept where dept_id=dept.id;


# 并且会产生重复的字段信息,例如员工里的部门编号和部门表里的id字段,所以在select 后指出需要查询的字段名称
# 案例:
select dept.name as 部门, dept.id 部门编号, emp.name 姓名, emp.id 员工编号, sex from emp, dept where dept.id=dept_id;

内连接查询语法

本质上就是笛卡尔积查询

# 语法
select * from table1 inner join table2;

# 案例
select * from emp inner join dept where dept_id = dept.id
# 其中inner可以省略,emp和dept的顺序也可以调换
# 这里的where可以用on替代

外连接查询

  • 包括没有匹配关系的数据,不常用,因为一般都会有外键约束对应关系

举例:

# 不存在外键关联的两张表
# 存在一些不正确的部门id
drop table if exists emp;
create table emp(id int primary key, name char(10), sex char(10), dept_id int );
insert into emp values(1,"大黄","m",1);
insert into emp values(2,"老王","m",2);
insert into emp values(3,"老李","w",30);

drop table if exists dept;
create table dept(id int primary key, name char(10));

insert into dept values(1, '市场');
insert into dept values(2, '财务');
insert into dept values(3, '行政');

左外连接查询

左边的表无论是否能够匹配都要完整显示,右边的仅展示匹配上的记录

# 需求:要查询所有员工以及其所属的部门信息
select * from emp left join dept on dept_id = dept.id;
# 注意,在外连接查询中不能够使用where关键字,必须使用on关键字专门来做表的对应关系

右外连接查询

右边的表无论是否能够匹配都要完整显示,左边的仅展示匹配上的记录

# 需求:要查询所有部门以及其所属的员工信息
select * from emp right join dept on dept.id = dept_id;

# 注意,哪个表放前面就先展示哪个表

全外连接查询

无论是否匹配成功,两边表的数据都要全部显示

# 需求:查询所有员工与所有部门的对应关系
select * from emp full join dept on dept.id = dept_id;
# 虽然不会报错,但也不是我们想要的结果

# mysql不支持全外连接

# 我们可以将左外连接查询的结果,和右外连接查询的结果,做一个合并

select * from emp left join dept on dept.id = dept_id
union
select * from emp right join dept on dept.id = dept_id;


# union的用法
select * from emp
union all
select * from emp;

# union将自动去除重复的记录
# union all 不去除重复

select sex,name from emp
union
select * from dept;
# 注意 union 必须保证两个查询结果列数相同,一般用在多个结果结构完全一致时

总结:外连接查询,查到的是没有对应关系的记录,但是这样的数据原本就是有问题的,所以最常用的还是内连接查询

内连接表示 只显示匹配成功的记录

外连接表示 没有匹配成功的也要显示

多表查询案例:

create table stu(id int primary key auto_increment, name char(10));

create table tea(id int primary key auto_increment, name char(10));

create table tsr(
    id int primary key auto_increment, 
    t_id int, 
    s_id int, 
    foreign key(t_id) references tea(id), 
    foreign key(s_id) references stu(id)
	);

insert into stu values(null, '张三'), (null, '李四');
insert into tea values(null, 'nick'), (null, 'jerry');
insert into tsr values(null,1,1),(null,1,2),(null,2,2);

# nick老师教过哪些人?
select tea.name, stu.name from tea join tsr join stu on tea.id = t_id and stu.id = s_id where tea.name = 'nick';

注意:

在查询数据中,应该将上述知识合并使用,特别是子查询和内连接查询,如果面临多表联合查询,应该先理清楚步骤,一步一步实现,可以将一部分的查询结果搭建成一个临时表,再联合其他表进行查询.

例如:

# 查询平均成绩大于80分的同学的姓名以及平均成绩
# 1. 根据学生id分组,查出所有平均成绩大于80的学生id
select student_id, avg(num) from score group by student_id having avg(num) > 80;
#2. 将查询结果作为一个临时表,如果要使用临时表的数据,就可以写上as a 然后后面就用 a.字段 去使用
(select student_id, avg(num) from score group by student_id having avg(num) > 80) as a ;
#3. 将临时表数据与学生表连接
select * from student join (select student_id, avg(num) from score group by student_id having avg(num) > 80) as a ;
#4. 进行一些筛选
select * from student join (select student_id, avg(num) from score group by student_id having avg(num) > 80) as a on sid = a.student_id;
posted @ 2019-07-16 19:18  abcde_12345  阅读(375)  评论(0编辑  收藏  举报