• MySQL表单的查询及分组聚合整理


    单表查询

    1.表与表关系

    1.1校区表 班级表 一对多

    ​ 校区表 一个校区可以有多个班级 一对多
    ​ 班级表 一个班级可不可以对应多个校区
    ​ 校区表 校区id 校区名称 校区城市 校区地址
    ​ 班级表 班级id 班级名称 开班日期 班主任 校区id
    ​ 多(foreign key)关联一这张表
    ​ 班级表创建foreign key关联校区表的校区id字段

    1.2学生表 班级表 多对多

    ​ 站在学生的角度上 一个学生属于多个班级 一对多
    ​ 站在班级的角度上 一个班级可以有多个学生么 多对一
    ​ 学生表 学生id 学生姓名 ...
    ​ 班级表 班级id 班级名称 ...
    ​ 产生第三张表
    ​ 一个字段是外键关联另一个表的主键
    ​ 另一个字段外键关联另一张表的主键

    1.3学生表 客户表 一对一

    ​ 一个客户对应一个学生
    ​ 学生表gid foreign key 关联客户表id主键
    ​ 并且gid还要设置为unique

    2.单表查询

    2.1有关查看的语句

    select user(); # 查看当前用户
    select database(); # 查看当前数据库
    select now(); # 查看当前时间
    

    2.2查看的基本语法

    # select *(全部) from 表名;
    select * from t1;
    # select 字段名 from 表名;
    select name from t1:
    # select 字段名,字段名,字段名 from 表名;
    select name, age from t1;
    

    2.3distinct(去重)

    # select distinct 字段 from 表;
    select distinct name from t1;
    # 对查出来的字段进行去重
    

    2.4查询能进行四则运算

    # select emp_name,salary*12 from 表
    select emp_name,salary*12 from t1
    # 字段salary参与了四则运算
    

    2.5concat

    对字段进行加工

    # select concat(字段,'字符串1',字段) from 表
    select concat(emp_name,' : ',salary) from employee;
    # 如果按照上面的写法,加工后的字段名就会变为concat(emp_name,' : ',salary),很难看
    
    select concat(emp_name,' : ',salary) as info from employee;
    select concat(emp_name,' : ',salary) info from employee;
    # 上面的两种写法效果相同,将字段名变为info
    
    # 加工后的效果为------>姓名:工资
    

    2.6concat_ws

    # select concat_ws('分隔符',字符串,字段1,字段2) info from employee;
    select concat_ws('|','信息',emp_name,salary) info from employee;
    # 使用分隔符将信息分隔开,可以加入字符串进行辅助拼接
    # 与concat类似可以修改字段名
    

    2.7case

    select(
        case # 语句头,相当于begin
        when emp_name = 'alex' then # when 条件 then
            concat(emp_name,'BIGSB') # 输出查询的字段,可加工
        when emp_name = 'jingliyang' then
            emp_name
        else					# 最后一条写else
            concat(emp_name,'sb')
        end # 语句尾
        ) as new_name # 字段重命名
    from employee;
    

    2.8where筛选行

    select * from 表 where 条件

    2.8.1范围查询

    ①>大于

    select age from t1 where age > 20;
    

    ②<小于

    select age from t1 where age < 20;
    

    ③>=大于等于

    select age from t1 where age >= 20;
    

    ④<=小于

    select age from t1 where age <= 20;
    

    ⑤=等于

    select age from t1 where age = 20;
    

    ⑥!=或<>不等于

    select age from t1 where age != 20;
    # 或
    select age from t1 where age <> 20;
    

    2.8.2模糊查询

    ①like:

    Ⅰ. % 一个百分号代表任意长度的任意字符

    # 'a%' 判断以a开头
    select name from t1 where name like 'a%';
    # '%ing' 判断以ing结尾
    select name from t1 where name like '%ing';
    # '%a%' 判断存在a
    select name from t1 where name like '%a%';
    

    Ⅱ. _ 一个下划线代表一个任意字符

    # 'a__' 判断以a开头的三个字符
    select name from t1 where name like 'a__';
    

    ②regexp

    实际上就是进行正则运算

    # '^a' 判断以a开头
    select name from t1 where name regexp '^a';
    # 'a$'判断以a结尾
    select name from t1 where name regexp 'a$';
    

    2.8.3 is与is not

    # 数据库中不能使用=去判断null,因此提供了is与is not 去判断null
    select name from t1 where name is null;
    select name from t1 where name is not null;
    

    2.8.4逻辑运算

    # and
    select name from t1 where name='alex' and age = 18;
    # or
    select name from t1 where name='alex' or name = 'sb';
    # not
    select name from t1 where not age > 30;
    

    3.表的修改

    # alter table 表名 rename 新表名;
    alter table t1 rename t2;
    # alter table 表名 add 新字段 类型(宽度) 约束;
    alter table t2 add post char(12) not null;
    # add 新字段 类型(宽度) 约束 after id
    alter table t2 add post char(12) not null after id; # 插在id之后
    # add 新字段 类型(宽度) 约束 first
    alter table t2 add post char(12) not null first; # 排头
    # alter table 表名 drop 字段名;
    alter table t1 drop post;
    # alter table 表名 change 旧字段 新字段 类型(宽度) 约束;
    alter table t1 change name new_name char(20) not null;
    alter table t1 change name name char(12) null;# 使name可以为空
    # alter table 表名 modify 存在的字段 新类型(新宽度) 新约束;
    alter table t1 modify name char(12) unique;
    alter table t1 modify name char(12) unique after id;
    

    4.数据操作补充

    # 增加
    # insert into 表名 value (1,'alex','female') 使用value一次只能增加一条记录
    insert into t1 value (1, 'alex', 'female');
    # insert into 表名 values (1,'alex','female'),(1,'alex','female');
    insert into t1 values (1, 'alex', 'female'),(2, 'alex', 'female')
    # insert into 表名(name,gender) values ('alex','female');    *****常用
    insert into t1(name, gender) values ('alex', 'female'),('alexsb', 'female');
    # insert into 表名(name,gender) select (username,sex) from 表2;
    insert into t1(name, gender) select (username, sex) from t2;
    
    
    # 修改
    # update 表名 set 字段=值1 where 条件
    update t1 set age=18 where age > 18;
    # update 表名 set 字段1=值1,字段2=值2 where 条件
    update t1 set age=18, sex='女' where age > 18 and sex='男';
    

    数据库中的分组与聚合

    1.数据库中关键字的执行顺序

    ①select 想要的列 from 表
    ②where 先从这张表中查询的行
    ③group by 分组
    ④having 对组过滤
    ⑤order by 排序
    ⑥limit 取一个区间

    2.分组(group by)

    使用情况:

    根据某个重复率比较高的字段进行的,
    这个字段有多少种可能就分成多少个组

    功能:

    ①分组
    ②去重
    注:一旦分组了就不能对具体某一条数据进行操作了

    数据表:

    # 使用group by
    select * from employee group by post;
    

    使用group by 时会出现一些问题:

    这里引出group_concat()

    select group_concat(emp_name) from employee where post='teacher' group by post;
    

    3.聚合(count,max,min,sum,avg)

    聚合:

    99.99%的情况都是和分组一起用的
    如果没有和分组一起用,默认一整张表是一组

    # count(id)  / count(*) 计数 :每个组对应几条数据
    select count(id) from employee;
    # max 求最大值: 这个组中某字段的最大值
    select max(hire_date) from employee;
    # min 求最大值: 这个组中某字段的最小值
    select min(hire_date) from employee;
    # avg 求平均值
    select avg(salary) from employee;
    # sum 求和值
    select sum(salary) from employee;
    

    4.过滤(having)

    # 就是一个对组进行筛选的条件
    # 要部门人数大于3个人的部门 count(id)>3
    select post from employee group by post having count(id)>3;
    

    5.排序(order by)

    # order by 字段(升序)
    select emp_name,age from employee order by age;
    # order by 字段 asc(升序)
    select emp_name,age from employee order by age asc;
    # order by 字段 desc(降序)
    select emp_name,age from employee order by age desc;
    
    # order by 字段1,字段2(对字段1升序,然后在字段1的基础下对字段2升序)
    select emp_name,age from employee order by age,salary;
    # order by 字段 asc,字段2 desc(对字段1升序,然后在字段1的基础下对字段2降序)
    select emp_name,age from employee order by age asc,salary desc;
    # order by 字段 desc,字段2 asc(对字段1降序,然后在字段1的基础下对字段2升序)
    select emp_name,age from employee order by age desc,salary asc;
    # order by 字段 desc,字段2 desc(对字段1降序,然后在字段1的基础下对字段2降序)
    select emp_name,age from employee order by age desc,salary desc;
    

    6.限制(limit)

    limit的用途:

    ①显示分页

    # limit m,n
        # 若写为limit n,默认m为0
        # 表示从m+1开始,取n条
        # limit 0,6 表示从1开始取6条
        # limit 6,6 表示从7开始取6条
        # limit 12,6 表示从13开始取6条
        # limit 18,6 表示从19开始取6条
        
    # 只显示一条信息
    select emp_name,age from employee limit 1;
    select emp_name,age from employee limit 0,1;# (两条效果相同)
    
    ################################################################
    # 有时面试中面试官会问 limit offset的用法,你会懵逼!
    # limit n offset m :从m+1开始,取n条 (*******************************)
    limit 1 offset 0; 与 limit 0,1; limit 1; 完全一样!!!!!
    

    ②取前n名

    # 跟order by一起用
    # 取最小年龄
    select emp_name,age from employee order by age limit 1;
    

    7.使用python操作数据库

    注:你的python中有pymysql模块

    import pymysql
    conn = pymysql.Connection(host='127.0.0.1', user='root', password="123",database='db1') # 相当于socket里面的conn
    cur = conn.cursor() # 记住
    
    lst = ['学python从开始到放弃|alex|人民大学出版社|50|2018-7-1',
    '学mysql从开始到放弃|egon|机械工业出版社|60|2018-6-3',
    '学html从开始到放弃|alex|机械工业出版社|20|2018-4-1',
    '学css从开始到放弃|wusir|机械工业出版社|120|2018-5-2',
    '学js从开始到放弃|wusir|机械工业出版社|100|2018-7-30']
    
    sql = 'insert into book values(%s,%s,%s,%s,%s)' # 格式化
    for i in lst:
        cur.execute(sql, (i.split('|'))) # 后面传参要用可迭代对象
        
    conn.commit() # 将数据提交至数据库写入
    cur.close() # 关闭
    conn.close() # 关闭
    

    多表查询

    1.连表查询前的序曲

    1.1数据准备

    #建表
    create table department(
    id int,
    name varchar(20) 
    );
    
    create table employee(
    id int primary key auto_increment,
    name varchar(20),
    sex enum('male','female') not null default 'male',
    age int,
    dep_id int
    );
    
    #插入数据
    insert into department values
    (200,'技术'),
    (201,'人力资源'),
    (202,'销售'),
    (203,'运营');
    
    insert into employee(name,sex,age,dep_id) values
    ('egon','male',18,200),
    ('alex','female',48,201),
    ('wupeiqi','male',38,201),
    ('yuanhao','female',28,202),
    ('liwenzhou','male',18,200),
    ('jingliyang','female',18,204)
    ;
    

    1.2笛卡尔积

    先计算两张表的笛卡尔积,再根据用户给出的条件进行筛选

    # 连表
    select * from employee,department;
    

    因此我们可以使用where来进行筛选:

    select * from employee,department where dep_id = department.id;
    

    但是这里也会存在问题,我们这里通过where来进行连表操作,导致where字段被占用了,无法对后续的记录进行筛选.因此这个连表操作是错误的!

    2.连表操作

    概念:原来是两张表,现在拼成一张表,所有的操作都像是操作一张表一样了

    2.1内连接

    # 内连接  inner join ... on 连接条件
    # select * from 表1 inner join 表2 on 条件
    select * from employee inner join department on dep_id = department.id;
           # employee --> dep_id: 200,201,202,204
           # department --> id : 200,201,202,203
    # 内连接 :只显示两张表中互相匹配的项,其他不匹配的不显示
    

    2.2外链接

    2.2.1左外连接

    # 左外连接 left join .. on
    # select * from 表1 left join 表2 on 条件
    select * from employee left join department on dep_id = department.id;
    # 不管左表中是不是匹配上都会显示所有内容
    
    select * from department left join employee  on dep_id = department.id;
    # 不管左表中是不是匹配上都会显示所有内容
    

    2.2.2右外链接

    # 右外连接 right join .. on
    # select * from 表1 right join 表2 on 条件
    select * from employee right join department on dep_id = department.id;
    # 不管右表中是不是匹配上都会显示所有内容
    

    2.2.3全外链接

    mysql不支持full join 的写法,但是可通过union来实现全外连接

    select * from department left join employee  on dep_id = department.id
    union
    select * from department right join employee on dep_id = department.id;
    

    3.子查询

    3.1概念

    1:子查询是将一个查询语句嵌套在另一个查询语句中。
    2:内层查询语句的查询结果,可以为外层查询语句提供查询条件。
    3:子查询中可以包含:IN、NOT IN、ANY、ALL、EXISTS 和 NOT EXISTS等关键字
    4:还可以包含比较运算符:= 、 !=、> 、<等

    3.2实例

    in:

    # 存在年龄大于25岁员工的部门
    select distinct dep_id from employee where age>25;
    # 查询年龄大于25的员工的部门id并去重
    select * from department where id in (select distinct dep_id from employee where age>25);
    # 使用in 去筛选
    

    exists:

    select * from employee
    where exists
    (select id from department where id=200);
    # 使用EXISTS关键字时,内层查询语句不返回查询的记录,而是返回一个真假值,True或False
    # 当返回True时,外层查询语句将进行查询;当返回值为False时,外层查询语句不进行查询.
    

    4.连表查询与子查询

    问题a:

    # a.查询平均年龄在25岁以上的部门名
    # 第一步:求部门的平均年龄>25岁的 部门id
    select dep_id from employee group by dep_id having avg(age)>25;
    # 第二步:构建子查询根据部门id求部门名
    select name from department where id in (select dep_id from employee group by dep_id having avg(age)>25);
    

    问题b:

    # b.查询平均年龄在25岁以上的部门名,平均年龄的值
    # 方法1:
    # 第一步:先查部门的平均年龄>25岁的部门id,平均年龄
    select dep_id,avg(age) from employee group by dep_id having avg(age) > 25;
    # 第二步:查出结果在之后再连表
    select name,avg_age from department as d right join (select dep_id,avg(age) as avg_age from employee group by dep_id having avg(age) > 25) as t on d.id = t.dep_id;
    

    总结:

    ①如果最终需要的结果只出现在一张表中,可以用子查询解决问题
    ②如果最终需要的结果出现在两个表中,那么最后用的一定是连表查询

    5.补充select的用法

    select还能这么使用:

    数据准备:

    create table employee(
    id int not null unique auto_increment,
    name varchar(20) not null,
    sex enum('male','female') not null default 'male', #大部分是男的
    age int(3) unsigned not null default 28,
    hire_date date not null,
    post varchar(50),
    post_comment varchar(100),
    salary double(15,2),
    office int, #一个部门一个屋子
    depart_id int
    );
    
    
    insert into employee(name,sex,age,hire_date,post,salary,office,depart_id) values
    ('egon','male',18,'20170301','老男孩驻沙河办事处外交大使',7300.33,401,1), #以下是教学部
    ('alex','male',78,'20150302','teacher',1000000.31,401,1),
    ('wupeiqi','male',81,'20130305','teacher',8300,401,1),
    ('yuanhao','male',73,'20140701','teacher',3500,401,1),
    ('liwenzhou','male',28,'20121101','teacher',2100,401,1),
    ('jingliyang','female',18,'20110211','teacher',9000,401,1),
    ('jinxin','male',18,'19000301','teacher',30000,401,1),
    ('成龙','male',48,'20101111','teacher',10000,401,1),
    
    ('歪歪','female',48,'20150311','sale',3000.13,402,2),#以下是销售部门
    ('丫丫','female',38,'20101101','sale',2000.35,402,2),
    ('丁丁','female',18,'20110312','sale',1000.37,402,2),
    ('星星','female',18,'20160513','sale',3000.29,402,2),
    ('格格','female',28,'20170127','sale',4000.33,402,2),
    
    ('张野','male',28,'20160311','operation',10000.13,403,3), #以下是运营部门
    ('程咬金','male',18,'19970312','operation',20000,403,3),
    ('程咬银','female',18,'20130311','operation',19000,403,3),
    ('程咬铜','male',18,'20150411','operation',18000,403,3),
    ('程咬铁','female',18,'20140512','operation',17000,403,3)
    ;
    

    实例:

    # 求每个部门最早入职的员工姓名
    select (select t2.name from employee as t2 where t2.post=t1.post order by hire_date desc limit 1) from employee as t1 group by post;
    
  • 相关阅读:
    编译器优化 → C关键字volatile → memory破坏描述符zz
    Mybatis 控制台打出SqlLog的设置
    J2EE ssm框架服务启动项内存加载数据及读取。
    Oracle 同步表权限分配(同义词)
    iOS开发雕虫小技之傻瓜式定位神器超简单方式解决iOS后台定时定位
    Oracle分页查询SQL实现
    iOS新建项目基本配置
    DP之子序列问题
    图论之最小生成树
    基础数论算法
  • 原文地址:https://www.cnblogs.com/zheng0907/p/12743101.html
Copyright © 2020-2023  润新知