day42

#Mysql基本语法(二)    
#一. 外键及外键的变种: (*********************************************************)
    #缘由:把所有数据都存放于一张表的弊端
         1、表的组织结构复杂不清晰
         2、浪费空间
         3、扩展性极差
                    
         解决方法:
                    
               重新设计一张表, 这张表 中存放部门的相关信息
        
    #1. 唯一索引:
        
        create table t5(
            id int,
            num int,
            unique(num)
        )engine=Innodb charset=utf8;
        
        作用:    
            num列的值不能重复
            加速查找
            
        create table t6(
            id int,
            num int,
            unique(id, num)
        )engine=Innodb charset=utf8;
        
        联合唯一索引作用:    
            num列和id列的值不能重复
            加速查找
        
        create table t6(
            id int,
            num int,
            unique(id, num......)
        )engine=Innodb charset=utf8;


    #2. 一对多:    
        #2-1 
            #部门表:
            
                create table department (
                    id  int auto_increment primary key, 
                    depart_name varchar(32)  not null  default ''
                )engine=Innodb charset=utf8;
                
                insert into department (depart_name) values ('公关'), ('关关'),('关公');
            #用户信息表:    
                create table userinfo (    
                    id  int auto_increment primary key, 
                    name varchar(32) not null default '',
                    depart_id int not null  default 1,
                    
                    # constraint 外键名(fk_userinfo_depart) foreign key (列名(depart_id)) references 表名(department)(关联的列名(id)),
                    constraint fk_userinfo_depart foreign key (depart_id) references department(id)
                
                )engine=Innodb charset=utf8;
                
                
                insert into userinfo (name, depart_id) values ('root1', 1);
                insert into userinfo (name, depart_id) values ('root2', 2);  错误的
                
                注意:
                    创建多个外键的时候, 名称不能一样
                
            #ps:
                    1. 不能将创建外键的语句单独拿出来
                       
                       alter table userinfo add constraint fk_userinfo_depart foreign key (depart_id) references department(id);
                       alter table userinfo drop foreign key 外键名称(fk_userinfo_depart );
                    
                    2. 外键关联的时候, 必须关联的是表的主键ID
                    
                    3. 练习的时候, 将语句写在文本中, 然后考过去执行
                    
                    4. 主键索引 : 加速查找 + 不能为空 + 不能重复

        #2-2、寻找表与表之间的关系的套路
            举例:emp表   dep表
            步骤一:
                part1:
                1、先站在左表emp的角度
                2、去找左表emp的多条记录能否对应右表dep的一条记录
                3、翻译2的意义:
                    左表emp的多条记录==》多个员工
                    右表dep的一条记录==》一个部门

                    最终翻译结果:多个员工是否可以属于一个部门?
                    如果是则需要进行part2的流程

                part2:
                1、站在右表dep的角度
                2、去找右表dep的多条记录能否对应左表emp的一条记录
                3、翻译2的意义:
                    右表dep的多条记录==》多个部门
                    左表emp的一条记录==》一个员工

                    最终翻译结果:多个部门是否可以包含同一个员工

                    如果不可以,则可以确定emp与dep的关系只一个单向的多对一
                    如何实现?
                        在emp表中新增一个dep_id字段,该字段指向dep表的id字段


       # 2-3、foreign key会带来什么样的效果?
            #1、约束1:在创建表时,先建被关联的表dep,才能建关联表emp

            create table dep(
                id int primary key auto_increment,
                dep_name char(10),
                dep_comment char(60)
            );

            create table emp(
                id int primary key auto_increment,
                name char(16),
                gender enum('male','female') not null default 'male',
                dep_id int,
                foreign key(dep_id) references dep(id)
            );

            #2、约束2:在插入记录时,必须先插被关联的表dep,才能插关联表emp
            insert into dep(dep_name,dep_comment) values
            ('sb教学部','sb辅导学生学习,教授python课程'),
            ('外交部','老男孩上海校区驻张江形象大使'),
            ('nb技术部','nb技术能力有限部门');


            insert into emp(name,gender,dep_id)  values
            ('alex','male',1),
            ('egon','male',2),
            ('lxx','male',1),
            ('wxx','male',1),
            ('wenzhou','female',3);


            #3、约束3:更新与删除都需要考虑到关联与被关联的关系
            解决方案:
            1、先删除关联表emp,再删除被关联表dep,准备重建
            mysql> drop table emp;
            Query OK, 0 rows affected (0.11 sec)

            mysql> drop table dep;
            Query OK, 0 rows affected (0.04 sec)


        #2-4、重建:新增功能,同步更新,同步删除
            create table dep(
                id int primary key auto_increment,
                dep_name char(10),
                dep_comment char(60)
            );

            create table emp(
                id int primary key auto_increment,
                name char(16),
                gender enum('male','female') not null default 'male',
                dep_id int,
                foreign key(dep_id) references dep(id)
                on update cascade
                on delete cascade
            );
            insert into dep(dep_name,dep_comment) values
            ('sb教学部','sb辅导学生学习,教授python课程'),
            ('外交部','老男孩上海校区驻张江形象大使'),
            ('nb技术部','nb技术能力有限部门');


            insert into emp(name,gender,dep_id)  values
            ('alex','male',1),
            ('egon','male',2),
            ('lxx','male',1),
            ('wxx','male',1),
            ('wenzhou','female',3);


        #2-5、同步删除
            mysql> select * from dep;
            +----+------------------+------------------------------------------------------------------------------------------+
            | id | dep_name         | dep_comment                                                                              |
            +----+------------------+------------------------------------------------------------------------------------------+
            |  1 | sb教学部         | sb辅导学生学习,教授python课程                                                           |
            |  2 | 外交部           | 老男孩上海校区驻张江形象大使                                                             |
            |  3 | nb技术部         | nb技术能力有限部门                                                                       |
            +----+------------------+------------------------------------------------------------------------------------------+
            3 rows in set (0.00 sec)

            mysql> select * from emp;
            +----+------------------+--------+--------+
            | id | name             | gender | dep_id |
            +----+------------------+--------+--------+
            |  1 | alex             | male   |      1 |
            |  2 | egon             | male   |      2 |
            |  3 | lxx              | male   |      1 |
            |  4 | wxx              | male   |      1 |
            |  5 | wenzhou          | female |      3 |
            +----+------------------+--------+--------+
            5 rows in set (0.00 sec)

            mysql> delete from dep where id=1;
            Query OK, 1 row affected (0.02 sec)

            mysql> select * from dep;
            +----+------------------+------------------------------------------------------------------------------------------+
            | id | dep_name         | dep_comment                                                                              |
            +----+------------------+------------------------------------------------------------------------------------------+
            |  2 | 外交部           | 老男孩上海校区驻张江形象大使                                                             |
            |  3 | nb技术部         | nb技术能力有限部门                                                                       |
            +----+------------------+------------------------------------------------------------------------------------------+
            2 rows in set (0.00 sec)

            mysql> select * from emp;
            +----+------------------+--------+--------+
            | id | name             | gender | dep_id |
            +----+------------------+--------+--------+
            |  2 | egon             | male   |      2 |
            |  5 | wenzhou          | female |      3 |
            +----+------------------+--------+--------+
            2 rows in set (0.00 sec)

        #2-6、同步更新
            mysql> select * from emp;
            +----+------------------+--------+--------+
            | id | name             | gender | dep_id |
            +----+------------------+--------+--------+
            |  2 | egon             | male   |      2 |
            |  5 | wenzhou          | female |      3 |
            +----+------------------+--------+--------+
            2 rows in set (0.00 sec)

            mysql> update dep set id=200 where id =2;
            Query OK, 1 row affected (0.04 sec)
            Rows matched: 1  Changed: 1  Warnings: 0

            mysql> select * from dep;
            +-----+------------------+------------------------------------------------------------------------------------------+
            | id  | dep_name         | dep_comment                                                                              |
            +-----+------------------+------------------------------------------------------------------------------------------+
            |   3 | nb技术部         | nb技术能力有限部门                                                                       |
            | 200 | 外交部           | 老男孩上海校区驻张江形象大使                                                             |
            +-----+------------------+------------------------------------------------------------------------------------------+
            2 rows in set (0.00 sec)

            mysql> select * from emp;
            +----+------------------+--------+--------+
            | id | name             | gender | dep_id |
            +----+------------------+--------+--------+
            |  2 | egon             | male   |    200 |
            |  5 | wenzhou          | female |      3 |
            +----+------------------+--------+--------+
            2 rows in set (0.00 sec)
            
    #3. 一对一:
            左表的一条记录唯一对应右表的一条记录,反之也一样
            用户表:
                id    name     age  
                1      zekai    23  
                2      eagon    34
                3      lxxx     45
                4      owen     83

            博客表:
                id            url          user_id  (外键 + 唯一约束unique)
                1       /linhaifeng       2
                2       /zekai              1
                3       /lxxx             3
                4       /lxxx             4
    

    #4.  多对多:
            两张表之间是一个双向的多对一关系,称之为多对多
            如何实现?
            建立第三张表,该表中有一个字段fk左表的id,还有一个字段是fk右表的id
            
            用户表:
                id    name    phone 
                1    root1    1234
                2    root2    1235
                3    root3    1236
                4    root4    1237
                5    root5    1238
                6    root6    1239
                7    root7    1240
                8    root8    1241
                
            主机表:
            
                id    hostname    
                1    c1.com    
                2    c2.com    
                3    c3.com    
                4    c4.com    
                5    c5.com    

            为了方便查询, 用户下面有多少台主机以及某一个主机上有多少个用户, 我们需要新建第三张表:
                user2host:
                
                    id    userid    hostid
                        1    1    1
                        2    1    2
                        3    1    3
                        4    2    4
                        5    2    5
                        6    3    2
                        7    3    4    
            创建的时候, userid 和 hostid 必须是外键, 然后联合唯一索引 unique(userid, hostid)
            
            Django orm 也会设计
            


#二. 数据行的操作:
        
        增:
            insert into 表名 (列名1, 列名2,) values(值1, 值2);
            insert into 表名 (列名1, 列名2,) values(值1, 值2),(值1,值2),(值n,值n);
            
            insert into 表名 (列名1, 列名2,) select 列名1, 列名2 from 表名;
            
        删除:
            delete from 表名; 
            
            delete from 表名 where id > 10
            delete from 表名 where id < 10
            delete from 表名 where id <= 10
            delete from 表名 where id >= 10
            delete from 表名 where id != 10 
            delete from 表名 where id = 10 and name='xxx';  and : 并且 两个条件都必须要成立
            delete from 表名 where id = 10 or name='xxx';   or :  或者 只要满足一个条件成立
        修改:
            update 表名  set name='zekai', age=23 where id > 10;
            
        查询:
            
            基本:
                select * from 表名;
                select name , age from 表名;
            
            高级:
                
                a. where 条件查询:
                    select * from 表名 where  id=10;
                    select * from 表名 where  id >10 and id<15;
                    select * from 表名 where  id > 10;
                    != : 不等与
                    >= <= 
                    
                    
                    between and: 闭区间 
                        select * from t4 where id between 9 and 12;
                    
                    in: 在某一个集合中
                        select * from t4 where id in (9,10,11....);
                        
                        
                        select * from t4 where id in (select id from t3 where id between 2 and 4)
                        
                        是可以这样使用的, 但是不建议大家使用;
                
                b. 通配符:
                    alex
                    
                    select * from 表 where name like 'ale%'  - ale开头的所有(多个字符串)
                    select * from 表 where name like 'ale_'  - ale开头的所有(一个字符)

                c.     限制取几条:
                        
                        select * from 表名 limit 索引偏移量, 取出多少条数据;
                        
                        
                        select * from t3 limit 0, 10;  第一页
                        select * from t3 limit 10, 10;  第二页
                        
                        page = input('page:')
                        
                            page    索引偏移量      数据量(offset)
                              1         0              10
                              2         10             10
                              3         20             10
                              4         30             10
                              
                              page   (page-1)*offset   offset
                        
                        分页核心SQL:
                        
                            select * from t3 limit (page-1)*offset, offset;
                
                d.  排序:
                        
                        order by
                        
                        降序:
                            select * from t4 order by 列名 desc; descending
                        
                        升序:
                            select * from t4 order by 列名 asc; ascending
                
                        
                        多列:
                            
                            create table t7(
                            
                                id int auto_increment primary key,
                                num int not null default 0,
                                age int not null default 0
                            )charset=utf8;
                            
                            insert into t7 (num, age) values (2, 12),(3,13),(4, 12);
                        
                            select * from t4 order by num desc, name asc;
                            
                            如果前一列的值相等的话, 会按照后一列的值进行进一步的排序.
                
                e.  分组
                        
                        select age, 聚合函数(count(num)/sum(num)/max(num)/min(num)/avg(num)) from 表名 group by 列名;
                        
                        
                        select age, avg(num) from t7 group by age;
                         
                        select age, count(num) from t7 group by age;
                        
                        select age, count(num) as cnt from t7 group by age;  显示别名 as
                    
                        having的二次删选:
                            select age, count(num) as cnt from t7 group by age  having cnt>1;
                            
                        where 和 having的区别:
                            1). having与where类似,可筛选数据
                            2). where针对表中的列发挥作用,查询数据
                            3). having针对查询结果中的列发挥作用,二次筛选数据, 和group by配合使用
                            4). where不能用聚合函数,而having是可以用聚合函数,这也是他们俩最大的区别
                        
                        #设置sql_mode为only_full_group_by,意味着以后但凡分组,只能取到分组的依据
                        mysql> set global sql_mode="strict_trans_tables,only_full_group_by";

                        #每个部门的最高工资
                        select post,max(salary) from emp group by post;
                        select post,min(salary) from emp group by post;
                        select post,avg(salary) from emp group by post;
                        select post,sum(salary) from emp group by post;
                        select post,count(id) from emp group by post;



                        #group_concat(分组之后用)
                        select post,group_concat(name) from emp group by post;
                        select post,group_concat(name,"_SB") from emp group by post;
                        select post,group_concat(name,": ",salary) from emp group by post;
                        select post,group_concat(salary) from emp group by post;

                        # 补充concat(不分组时用)
                        select name as 姓名,salary as 薪资 from emp;

                        select concat("NAME: ",name) as 姓名,concat("SAL: ",salary) as 薪资 from emp;

                        # 补充as语法
                        mysql> select emp.id,emp.name from emp as t1; # 报错
                        mysql> select t1.id,t1.name from emp as t1;


                        # 查询四则运算
                        select name,salary*12 as annual_salary from emp;
                
                f.  连表操作
                        select * from userinfo, department; (笛卡尔积)
                        
                        select * from userinfo, department where userinfo.depart_id=department.id;
                        
                        1、1、内连接:把两张表有对应关系的记录连接成一张虚拟表
                        select * from emp inner join dep on emp.dep_id = dep.id;
                    
                        2、左连接:
                        
                            select * from userinfo left join department on userinfo.depart_id=department.id;
                            左边的表全部显示, 右边没有用到不显示
                        
                        3、右连接:
                            
                            select * from userinfo right join department on userinfo.depart_id=department.id;
                            右边的表全部显示, 左边没关联的用null表示
                        
                        4、全连接:在内连接的基础上,保留左、右边没有对应关系的记录
                            select * from emp left join dep on emp.dep_id = dep.id
                            union
                            select * from emp right join dep on emp.dep_id = dep.id;
                        
                        ps: 
                            a.只需要记住左连接 left join
                            
                            b.可以连接多张表 通过某一个特定的条件
                e. distinct去重
                        select distinct post,avg(salary) from emp
                        where age >= 30
                        group by post
                        having avg(salary) > 10000;
                            
            注意查询的顺序:
                语法:
                    select distinct 查询字段1,查询字段2,。。。 from 表名
                        where 分组之前的过滤条件
                        group by 分组依据
                        having 分组之后的过滤条件
                        order by 排序字段
                        limit 显示的条数;
                    #用函数模拟语法的执行顺序
                        def from(dir,file):
                            open('%s\%s' %(dir,file),'r')
                            return f

                        def where(f,pattern):
                            for line in f:
                                if pattern:
                                    yield line


                        def group():
                            pass

                        def having():
                            pass


                        def distinct():
                            pass


                        def order():
                            pass


                        def limit():
                            pass



                        def select():
                            res1=from()
                            res2=where(res1,pattern)
                            res3=group(res2,)
                            res4=having(res3)
                            res5=distinct(res4)
                            res6=order(res5)
                            limit(res6)
                select name,sum(score) from 表 where id > 10 group by score having age> 12  order by age desc limit 2, 10 
posted @ 2019-06-13 23:43  呼吸决定丶  阅读(79)  评论(0)    收藏  举报