• mysql数据库与python


    数据库

    参考网站

    知乎

    #数据
    	1.不同的人把相同的数据随意的存到一个文件中,数据的格式不一定相同
        2.软件开发目录规范
        	规定了数据存放的位置,db目录
        3.将数据保存到一个公共的地方,查找数据的时候就来这个地方查找
            
    #数据库之mysql   
    	数据库本质上就是一款基于网络通信的cs架构的应用软件  
        任何基于网络通信的软件,底层使用的都是socket
        MySQL不单单支持MySQL客户端来操作,也支持其他编程语言使用代码直接操作,为了解决语言的沟通问题,数据库制定了统一的语言--SQL语句
        mysql其实就是一款远程操作文件的软件,这一点与git、mvn类似
        
        #服务端
        	基于socket通信
            收发消息
            SQL语句(公共的标准)
        
        #客户端(自带的客户端、第三方软件)
        	基于socket通信
            收发消息
            SQL语句(公共的标准)
        
    #数据管理系统DBMS
    #数据库的分类
    	关系型数据库,数据与数据之间有关联、限制
        	MySQL、oracle、SQLserver、sqllite、db2
            #关系型数据库通常都是表结构(Excel),使用关系型数据库之前需要确定表结构、字段
        非关系型数据库
        	redis、mongodb(文档型数据库)、memcache
            #通常以键值对的方式存储数据
    

    数据库的安装与基本使用

    #可以把mysql看成是一款支持远程操作文件的软件
    	库			相当于文件夹
        表			相当于文件
        记录			文件内的一行行的数据
        表头:表格的第一行数据
        字段:字段名+字段类型
        
    #表头由字段组成
    
    #mysql中的注释
    	1.#号
        2.--
    

    下载mysql

    #mysql的下载
    	官网下载社区版(包括客户端、服务端),解压
    	#服务端
        	mysqld
        #客户端
        	mysql
        #启动mysql
        	1.切换到bin目录
        	2.执行mysqld、mysql
    

    启动mysql(mysqld)

    #启动mysql
    	#mysql下载好之后,对于文件的修改、执行,最好使用管理员身份
        Windows+r 启动的是普通用户,不是管理员
        #以管理员启动CMD(命令提示符)的方法
        	1.在开始栏找到命令提示符
        	2.鼠标右键以管理员身份运行
        	3.输入命令,启动mysqld(mysql服务端)
              C:windowssystem32>F:
              F:>cd F:appmysql-5.6.45-winx64in
              F:appmysql-5.6.45-winx64in>
        	  F:appmysql-5.6.45-winx64in>mysqld
        	4.使用Windows+r再运行一个CMD窗口,启动mysql客户端
              C:Users17575>F:
              F:>cd F:appmysql-5.6.45-winx64in
              F:appmysql-5.6.45-winx64in>mysql -h127.0.0.1 -P3306 -uroot -p
              Enter password:   #mysql没有初始密码
              mysql>
    

    进程

    #查看进程
    F:>tasklist |findstr mysqld
    mysqld.exe                   13496 Console                    4    454,476 K
    
    #杀死进程(必须以管理员身份运行)
    F:>taskkill /F /PID 13496
    成功: 已终止 PID 为 13496 的进程。
    

    环境变量

    #环境变量  
        将启动文件所在的路径添加到环境变量中
        1.鼠标右键此电脑,属性
        2.高级系统设置,环境变量
        3.双击系统变量中的Path,新建'要添加的环境变量路径'即可
        4.重启mysql服务端、CMD终端
        	#启动服务端
        		C:windowssystem32>mysqld
        	#启动客户端
        		C:windowssystem32>mysql -uroot -p
    			Enter password:
    

    mysql开机自启动

    #将mysqld制作成系统服务
    	C:windowssystem32>mysqld --install
    	Service successfully installed.
        #此时mysql就可以开机自启动了,service.msc图形化可以设置mysql的状态
        
    #mysql启动
    	1.CMD命令行启动
        	F:appmysql-5.6.45-winx64in>net stop mysql
    		F:appmysql-5.6.45-winx64in>net start mysql
        2.Windows+r,输入services.msc,使用图形化启动
    

    修改mysql数据库root密码

    #实例,先确认,再修改 
    	C:windowssystem32>mysqladmin -uroot -p password 123
    	Enter password:
    	Warning: Using a password on the command line interface can be insecure.
    
    #修改密码格式
    	mysqladmin -uroot -p原密码 password 新密码;
        update mysql.user set password=password(123) where user='root' and host='localhost';
    

    '破解'mysql的管理员密码

    #'破解'
    	1.先将已经启动的服务端停掉
        	C:windowssystem32> tasklist |findstr mysqld
    		mysqld.exe                   27428 Services                   0     93,272 K
    		C:windowssystem32> taskkill /F /PID 27428
    		成功: 已终止 PID 为 27428 的进程。
        
        2.跳过用户名和密码的验证功能,启动服务端(跳过授权表)
        	C:windowssystem32> mysqld --skip-grant-tables 
        3.以管理员的身份再开启一个CMD窗口,使用mysql客户端连接mysql服务端
        	C:windowssystem32> mysql -uroot
        4.修改管理员密码
        	mysql> update mysql.user set password=password(1) where user='root' and host='localhost';
        5.关闭服务端,再以检验密码的方式启动(正常启动就行)
        	F:appmysql-5.6.45-winx64in>mysql -uroot -p
    		Enter password: *
    

    配置文件

    #s查看mysql服务端的简介
    mysql> s
    --------------
    mysql  Ver 14.14 Distrib 5.6.45, for Win64 (x86_64)
    
    Connection id:          1
    Current database:
    Current user:           root@localhost
    SSL:                    Not in use
    Using delimiter:        ;
    Server version:         5.6.45 MySQL Community Server (GPL)
    Protocol version:       10
    Connection:             localhost via TCP/IP
    Server characterset:    latin1
    Db     characterset:    latin1
    Client characterset:    gbk
    Conn.  characterset:    gbk
    TCP port:               3306
    Uptime:                 1 hour 1 min 17 sec
    
    Threads: 1  Questions: 5  Slow queries: 0  Opens: 67  Flush tables: 1  Open tables: 60  Queries per second avg: 0.001
                                
    #Windows中,配置文件的后缀通常都是.ini结尾的(给人看的)
    #mysql自带的配置文件不要修改,但是你可以自己新建一个配置文件my.ini,mysql服务端在启动的时候就会加载my.ini文件内的配置
    #修改了配置文件,一定要重启服务,这样才能让配置的修改生效,但是配置文件中,客户端配置的修改不重启服务也能生效
    
    #my.ini
    [mysqld]
    character-set-server=utf8
    collation-server=utf8_general_ci
    
    [client]	#第三方客户端
    default-character-set=utf8
    
    [mysql]		#mysql自带的客户端,每运行一次SQL语句就会运行配置文件中对应的配置
    default-character-set=utf8
    
    #重新查看mysql配置
    mysql> s
    --------------
    mysql  Ver 14.14 Distrib 5.6.45, for Win64 (x86_64)
    
    Connection id:          1
    Current database:
    Current user:           root@localhost
    SSL:                    Not in use
    Using delimiter:        ;
    Server version:         5.6.45 MySQL Community Server (GPL)
    Protocol version:       10
    Connection:             localhost via TCP/IP
    Server characterset:    utf8
    Db     characterset:    utf8
    Client characterset:    utf8
    Conn.  characterset:    utf8
    TCP port:               3306
    Uptime:                 19 sec
    
    Threads: 1  Questions: 5  Slow queries: 0  Opens: 67  Flush tables: 1  Open tables: 60  Queries per second avg: 0.263
    --------------
    

    数据库的增删改查

    修改数据库名参考

    delete与truncate的区别

    #库
    	增
        	create database db_name;
        查
        	show databases;
            show create database db_name;
            show engines;		#查看数据库存储引擎,mysql存储引擎默认为innodb
            show variables like 'default_storage_engine';	#正在使用的存储引擎
            set default_storage_engine=myisam;				#修改mysql数据库的存储引擎
        改
        	#数据库名不能直接修改
        	alter database db_name charset 'gbk'	#修改库的字符集
        删
        	drop database db_name;
    
    #表
    	#创建表的时候,要进入到指定的库下,use db_name;
        #查看当前所在的库,select database();
    	增
        	create table table_name(id int,name char(4))
        查
        	show tables;
            show create table table_name;
            desc table_name;		#查看表结构,等效于describe
    		describe table_name;
        改
        	alter table table_name rename new_table_name;		#修改表名
            alter table table_name change old_field_name new_field_name varchar(4)
        	alter table table_name modify name char(32);		#修改字段的属性
            
        删
        	drop table table_name;
            
    #数据
    	增
        	insert table_name value(1,'syy');
            insert table_name value(2,'ayy'),(3,'byy');
            insert table_name(name) value('xyy');
            insert table_name(id,name) value(5,'Xyy');
        查
        	select id,name from table_name;
            select * from table_name where id=5;
            select * from table_name where id =1 and name='syy';
            select * from table_name where id =1 or id=2;
            select * from table_name where not id =1;		#不包含NULL
        改
        	update table_name set id=4 where name='xyy';	#默认不区分大小写(Windows)
            update table_name set id=1,name='xxx' where id=1;
        删
        	delete from table_name where id=4 and name='xyy';
            delete from table_name;		#清空表
            truncate table_name;		#清空表
    

    存储引擎

    #存储引擎
    	不同的数据应该有不同的处理机制,这样的处理机制就是存储引擎工作的机制
        
    #查看mysql支持的存储引擎
    	mysql> show engines;
    
    #mysql存储引擎
    	innodb			mysql默认的存储引擎(5.1版本之后)
        myisam			老版本存储引擎(5.1版本之前)
        memory			数据存储在内存中,是一个内存引擎
        blackhole		无论存什么都会消失(黑洞)
    
    #innodb存储引擎的特点
    	1.支持事务
        2.支持行级锁,处理数据更加安全
        3.支持外键
        
    #myisam存储引擎的特点
    	1.查询数据更快
        
    #验证不同存储引擎的特点
    mysql> create table t1(id int) engine=innodb;
    mysql> create table t2(id int) engine=myisam;
    mysql> create table t3(id int) engine=blackhole;
    mysql> create table t4(id int) engine=memory;
    	#不同的表就对应了不同的文件(不同的存储引擎,一个表对应的文件个数不同)
        	1.innodb,一个表有两个文件,table_name.frm,该文件存储表结构,table_name.ibd,该文件存储表中的真实数据
            2.myisam,一个表有三个文件,table_name.frm,该文件存储表结构,table_name.MYD,该文件存储表中的真实数据,table_name.MYI,该文件存储表的索引
        	3.blackhole,一个表有一个文件,table_name.frm,该文件存储表结构,数据不需要存储到文件,所以没有table_name.ibd文件
        	4.memory,一个表有一个文件,table_name.frm,该文件存储表结构,数据存储到内存,不需要存储到文件,所以没有table_name.ibd文件
        #向不同的表中插入数据
    mysql> insert t1 value(1);
    mysql> insert t2 value(2);
    mysql> insert t3 value(3);		#数据立即消失
    mysql> insert t4 value(4);		#服务端重启,数据消失
    

    创建表的完整语法

    字符串char

    #
    create table table_name(
    	字段名1 类型[(宽度) 约束条件],
        字段名2 类型[(宽度) 约束条件],
        字段名3 类型[(宽度) 约束条件]
    	);
    
    #注意
    	1.字段名和字段类型是必须的,中括号内的参数都是可选参数
    	2.同一张表中字段名不能重复,字段的类型是可以重复的
    	3.创建表的SQL语句中,最后一个字段类型的后面不能加逗号
        #'类型'约束的是数据的存储类型,'约束条件'是数据的额外限制
        #mysql和Windows一样,对大小写不敏感
    
    #宽度	
    	宽度是字段的属性,是对数据的'个数'限制
    
    #例
    	字符宽度与数据插入
    mysql> create table test(name char);
    mysql> desc test;
    +-------+---------+------+-----+---------+-------+
    | Field | Type    | Null | Key | Default | Extra |
    +-------+---------+------+-----+---------+-------+
    | name  | char(1) | YES  |     | NULL    |       |		#默认宽度为1
    +-------+---------+------+-----+---------+-------+
    mysql> insert test value('syy');
    mysql> select * from test;
    +------+
    | name |
    +------+
    | s    |		#只能存储第一个字符,或者直接报错(数据库严格模式下)
    +------+
    
    #数据库的严格模式(默认是关闭的)
    	#开启的话,上例就会直接报错
        #关闭的话,上例中数据库会先截取字符,再插入数据
    sql_mode=NO_ENGINE_SUBSTITUTION,STRICT_TRANS_TABLES 	#关闭
    
    #例2
    	设置字段非空
    mysql> select * from test;
    +------+
    | name |
    +------+
    | s    |
    +------+
    mysql> insert test value(NULL);		#NULL为特殊字符
    mysql> select * from test;
    +------+
    | name |
    +------+
    | s    |
    | NULL |
    +------+
    mysql> alter table test modify name char not null;
    mysql> select * from test;
    +------+
    | name |
    +------+
    | s    |
    |      |
    +------+
    
    #char后面的数字是用来限制插入字符串的长度的
    mysql> create database test2;
    mysql> create table test2.test(name char(4));
    mysql> desc test2.test;
    +-------+---------+------+-----+---------+-------+
    | Field | Type    | Null | Key | Default | Extra |
    +-------+---------+------+-----+---------+-------+
    | name  | char(4) | YES  |     | NULL    |       |
    +-------+---------+------+-----+---------+-------+
    mysql> insert test2.test value('hahaha');
    mysql> select * from test2.test;
    +------+
    | name |
    +------+
    | haha |
    +------+
    

    字符串varchar

    #varchar(4)
    	char表示字符串的数据类型,后面的数字表示最大存储字符的个数,如果插入字符少了的话,那么就用空格填充,如果插入字符多了的话
        	严格模式开启,直接报错
            严格模式关闭,先截取再插入
    	varchar表示字符串的数据类型,后面的数字表示最大存储字符的个数,如果插入字符少了的话,那么就有几个存几个,如果插入字符多了的话
        	严格模式开启,直接报错
            严格模式关闭,先截取再插入
            
    #例
    mysql> create table test1(name char(4));
    mysql> create table test2(name varchar(4));
    mysql> insert test1 value('syyha');
    ERROR 1406 (22001): Data too long for column 'name' at row 1  #严格模式,直接报错
    mysql> insert test2 value('syyha');
    ERROR 1406 (22001): Data too long for column 'name' at row 1  #严格模式,直接报错
    mysql> insert test1 value('ha');
    mysql> insert test2 value('ha');
    mysql> select * from test1,test2;
    +------+------+
    | name | name |
    +------+------+
    | ha   | ha   |
    +------+------+
    	#使用关键字char_length(),统计某列字符长度
        	#mysql在存储char类型字段的时候,硬盘上确确实实存的是固定长度的数据,但是取出来的时候,mysql会自动将填充的空格去掉,所以该函数统计的字符长度并不包括插入数据的时候填充的空格
    mysql> select char_length(name) from test1;
    +-------------------+
    | char_length(name) |
    +-------------------+
    |                 2 |
    +-------------------+
    mysql> select char_length(name) from test2;
    +-------------------+
    | char_length(name) |
    +-------------------+
    |                 2 |
    +-------------------+
    	#设置sql_mode,修改字符统计的方法
    mysql> set global sql_mode="strict_trans_tables,PAD_CHAR_TO_FULL_LENGTH";	
    mysql> 
    		#重连数据库
    mysql> show variables like '%mode%';	#查看配置是否生效
    +----------------------------+---------------------------------------------+
    | Variable_name              | Value                                       |
    +----------------------------+---------------------------------------------+
    | binlogging_impossible_mode | IGNORE_ERROR                                |
    | block_encryption_mode      | aes-128-ecb                                 |
    | gtid_mode                  | OFF                                         |
    | innodb_autoinc_lock_mode   | 1                                           |
    | innodb_strict_mode         | OFF                                         |
    | pseudo_slave_mode          | OFF                                         |
    | slave_exec_mode            | STRICT                                      |
    | sql_mode                   | STRICT_TRANS_TABLES,PAD_CHAR_TO_FULL_LENGTH |
    +----------------------------+---------------------------------------------+
    	#重新使用关键字char_length(),统计某列字符长度
    mysql> select char_length(name) from test1;
    +-------------------+
    | char_length(name) |
    +-------------------+
    |                 4 |		#说明插入字符不足,char会填充
    +-------------------+
    mysql> select char_length(name) from test2;
    +-------------------+
    | char_length(name) |
    +-------------------+
    |                 2 |		#说明插入字符不足,varchar不会填充
    +-------------------+
    
    #char与varchar的区别
    	char定长
        	1.浪费空间
            2.存取速度快(按固定长度取即可)
        varchar变长(#推荐)
        	1.比较节省空间
            2.存取速度慢(存的时候需要给数据加一个报头,取的时候需要先查看数据对应的报头,再取出指定长度的数据)
    

    整型

    #TINYINT
    	范围是(-128,127),默认有负数,超出范围只会插入最大值或最小值
    
    #测试TINYINT的范围
    mysql> create table test(id tinyint);
    mysql> desc test;
    +-------+------------+------+-----+---------+-------+
    | Field | Type       | Null | Key | Default | Extra |
    +-------+------------+------+-----+---------+-------+
    | id    | tinyint(4) | YES  |     | NULL    |       |
    +-------+------------+------+-----+---------+-------+
    mysql> insert test value(-128),(127);
    mysql> insert test value(-129),(128);	#超出范围,插入最大值或最小值
    mysql> select * from test;
    +------+
    | id   |
    +------+
    | -128 |
    |  127 |
    | -128 |
    |  127 |
    +------+
    	#使用关键字unsigned修改tinyint范围,(0,255)
    mysql> alter table test modify id TINYINT unsigned;
    mysql> select * from test;
    +------+
    | id   |
    +------+
    |    0 |
    |  127 |
    |    0 |
    |  127 |
    +------+
    mysql> insert test value(-1),(256);
    mysql> select * from test;
    +------+
    | id   |
    +------+
    |    0 |
    |  127 |
    |    0 |
    |  127 |
    |    0 |
    |  255 |
    +------+
        
    #INT 
    	范围是(-2147483648,2147483647),默认有负数,超出范围只会插入最大值或最小值
        
    #测试INT范围
    mysql> create table test(id int);
    mysql> desc test;
    +-------+---------+------+-----+---------+-------+
    | Field | Type    | Null | Key | Default | Extra |
    +-------+---------+------+-----+---------+-------+
    | id    | int(11) | YES  |     | NULL    |       |		#默认为11,满足一般使用
    +-------+---------+------+-----+---------+-------+
    mysql> insert test value(-1111111111111111),(1111111111111111111111);
    mysql> select * from test;
    +-------------+
    | id          |
    +-------------+
    | -2147483648 |
    |  2147483647 |
    +-------------+
    	#使用关键字unsigned修改tinyint范围,(0,4294967295)
    mysql> alter table test modify id int unsigned;
    mysql> insert test value(-1111111111111111),(11111111111111111111111111111111);
    mysql> select * from test;
    +------------+
    | id         |
    +------------+
    |          0 |
    | 2147483647 |
    |          0 |
    | 4294967295 |
    +------------+
    	#整型后面的数字不是用来限制存储数据的长度的,而是用来控制展示数据的长度/位数的
        	#int后面的数字大于或等于8位,那么插入的数字中,有几位数字就直接存几位数字
            #int后面的数字小于8位的话,插入的数字位数不足的话,默认以空格填充,插入的数字等于或大于的话,直接存储
    mysql> alter table test modify id int(3);
    mysql> desc test;
    +-------+--------+------+-----+---------+-------+
    | Field | Type   | Null | Key | Default | Extra |
    +-------+--------+------+-----+---------+-------+
    | id    | int(3) | YES  |     | NULL    |       |
    +-------+--------+------+-----+---------+-------+
    mysql> insert test value(1234);
    mysql> select * from test;
    +-------+
    | id    |
    +-------+
    | 1234  |
    +-------+
        #使用关键字zerofill,修改数据类型int的数字填充方式(用0填充,无论int后面的数字是多少)
    mysql> create table test(id int(8) zerofill);
    mysql> insert test value(1),(12345678);
    mysql> select * from test;
    +----------+
    | id       |
    +----------+
    | 00000001 |
    | 12345678 |
    +----------+ 
    

    数据库sql严格模式

    #模糊匹配
    	like
        	%,匹配任多个个字符
            _,匹配任意一个字符
     
    #查看mysql配置中,变量名含有mode的变量名
    mysql> show variables like '%mode%';
    +----------------------------+------------------------+
    | Variable_name              | Value                  |
    +----------------------------+------------------------+
    | binlogging_impossible_mode | IGNORE_ERROR           |
    | block_encryption_mode      | aes-128-ecb            |
    | gtid_mode                  | OFF                    |
    | innodb_autoinc_lock_mode   | 1                      |
    | innodb_strict_mode         | OFF                    |
    | pseudo_slave_mode          | OFF                    |
    | slave_exec_mode            | STRICT                 |
    | sql_mode                   | NO_ENGINE_SUBSTITUTION |
    +----------------------------+------------------------+
    
    +----------------------------+---------------------------------------------+
    | Variable_name              | Value                                       |
    +----------------------------+---------------------------------------------+
    | binlogging_impossible_mode | IGNORE_ERROR                                |
    | block_encryption_mode      | aes-128-ecb                                 |
    | gtid_mode                  | OFF                                         |
    | innodb_autoinc_lock_mode   | 1                                           |
    | innodb_strict_mode         | OFF                                         |
    | pseudo_slave_mode          | OFF                                         |
    | slave_exec_mode            | STRICT                                      |
    | sql_mode                   | STRICT_TRANS_TABLES,PAD_CHAR_TO_FULL_LENGTH |
    +----------------------------+---------------------------------------------+
        
    #临时设置严格模式 ,立即生效
        set session sql_mode='STRICT_TRANS_TABLES';
        
    #永久设置严格模式,需要重新进入mysql客户端才能生效
        set global sql_mode='STRICT_TRANS_TABLES';
        
    #STRICT_TRANS_TABLES,SQL开启严格模式,SQL不会对数据再有剪切、默认等动作
    #PAD_CHAR_TO_FULL_LENGTH,验证length()函数在统计char和varchar上的区别
    #only_full_group_by,group_by使用SQL严格模式
    

    浮点型

    #浮点型
    	type(最大所有位数,最大小数位数)
    	float(255,30)		
        double(255,30)
        decimal(65,30)
        
    #区别
    	插入数据的精确度:float < double < decimal
        
    #例
    mysql> create table test1(id float(255,30));	
    mysql> create table test2(id double(255,30));
    mysql> create table test3(id decimal(65,30));
    mysql> insert test1 value(1.012345678901234567890123456789);
    mysql> insert test2 value(1.012345678901234567890123456789);
    mysql> insert test3 value(1.012345678901234567890123456789);
    mysql> select * from test1,test2,test3;
    1.012345671653747600000000000000 |
    1.012345678901234600000000000000 |
    1.012345678901234567890123456789 |
    
    #通常情况下,会将数字先转化为字符串,然后再存储数据库上,这样就不需要考虑浮点型的精度问题了
    

    日期类型

    #date,年月日
    
    #datetime,年月日时分秒
    
    #year,年
    
    #time,时分秒
    
    #例
    create table student(
    	id int,
        name char(4),
        born_year year,
        birth date,
        study_time time,
        reg_time datetime
    );
    mysql> desc student;
    +------------+----------+------+-----+---------+-------+
    | Field      | Type     | Null | Key | Default | Extra |
    +------------+----------+------+-----+---------+-------+
    | id         | int(11)  | YES  |     | NULL    |       |
    | name       | char(4)  | YES  |     | NULL    |       |
    | born_year  | year(4)  | YES  |     | NULL    |       |
    | birth      | date     | YES  |     | NULL    |       |
    | study_time | time     | YES  |     | NULL    |       |
    | reg_time   | datetime | YES  |     | NULL    |       |
    +------------+----------+------+-----+---------+-------+
    insert student values(1,'syy','2019','2019-12-21','11:11:00','2019-12-21 11:11:00');
    mysql> select * from student;
    +------+------+-----------+------------+------------+---------------------+
    | id   | name | born_year | birth      | study_time | reg_time            |
    +------+------+-----------+------------+------------+---------------------+
    |    1 | syy  |      2019 | 2019-12-21 | 11:11:00   | 2019-12-21 11:11:00 |
    +------+------+-----------+------------+------------+---------------------+
    

    枚举类型

    #枚举类型
    	多选一
    
    #例
    create table user(
    	id int,
        name char(16),
        gender enum('male','female','others')
    );
    desc user;
    +--------+--------------------------------+------+-----+---------+-------+
    | Field  | Type                           | Null | Key | Default | Extra |
    +--------+--------------------------------+------+-----+---------+-------+
    | id     | int(11)                        | YES  |     | NULL    |       |
    | name   | char(16)                       | YES  |     | NULL    |       |
    | gender | enum('male','female','others') | YES  |     | NULL    |       |
    +--------+--------------------------------+------+-----+---------+-------+
    insert user value(1,'syy','male');
    select * from user;
    +------+------------------+--------+
    | id   | name             | gender |
    +------+------------------+--------+
    |    1 | syy              | male   |
    +------+------------------+--------+
    

    集合类型

    #集合类型
    	多选多
    
    #例
    create table teacher(
    	id int,
        name char(16),
        gender enum('male','female','others'),
        hobby set('read','sleep','sanna','eat')
    );
    desc teacher;
    +--------+-----------------------------------+------+-----+---------+-------+
    | Field  | Type                              | Null | Key | Default | Extra |
    +--------+-----------------------------------+------+-----+---------+-------+
    | id     | int(11)                           | YES  |     | NULL    |       |
    | name   | char(16)                          | YES  |     | NULL    |       |
    | gender | enum('male','female','others')    | YES  |     | NULL    |       |
    | hobby  | set('read','sleep','sanna','eat') | YES  |     | NULL    |       |
    +--------+-----------------------------------+------+-----+---------+-------+
    insert teacher value(1,'syy','male','read,eat');	#集合也可以只选一个
    mysql> select * from teacher;
    +------+------------------+--------+----------+
    | id   | name             | gender | hobby    |
    +------+------------------+--------+----------+
    |    1 | syy              | male   | read,eat |
    +------+------------------+--------+----------+
    

    约束条件

    #约束条件
    	not null	非空(数据不能为空)
        default		给某个数据设置默认值
        unique		单列唯一(该列数据不能重复)
        			联合唯一(某一条数据的两列不能重复)
        primary key	主键,非空且唯一,innodb存储引擎规定:一个表必须有一个主键,且一个表最多只能有一个主键,当没有指定主键的时候:
        	1.将表中非空且唯一的字段,自动升级主键
            2.如果表中没有非空且唯一的字段的话,innodb存储引擎会自动添加一个隐藏的主键字段
            #通常每张表里面都应该有一个id字段,并设置该字段为主键
            #联合主键,多个字段联合起来作为表的一个主键,本质上还是一个主键
        auto_increment	自增,不能单独使用,必须先设置键再设置自增
            
    #例,非空
    mysql> create table t1(id int not null);
    mysql> insert t1 value(1),(null);
    ERROR 1048 (23000): Column 'id' cannot be null
    mysql> select * from t1;
    Empty set (0.00 sec)		#插入失败
    
    #例,默认值
    mysql> create table t2(id int default 999);
    mysql> insert t2 value();
    mysql> select * from t2;
    +------+
    | id   |
    +------+
    |  999 |
    +------+
    
    #例,单列唯一
    mysql> create table t3(id int unique);
    mysql> insert t3 value(1),(1);
    ERROR 1062 (23000): Duplicate(重复) entry '1' for key 'id
        
    #例,联合唯一
    mysql> create table t4(ip char(16),port int,unique(ip,port));
    mysql> desc t4;
    +-------+----------+------+-----+---------+-------+
    | Field | Type     | Null | Key | Default | Extra |
    +-------+----------+------+-----+---------+-------+
    | ip    | char(16) | YES  | MUL | NULL    |       |
    | port  | int(11)  | YES  |     | NULL    |       |
    +-------+----------+------+-----+---------+-------+
    mysql> insert t4 value('10.0.0.1',8080);
    mysql> insert t4 value('10.0.0.1',8081);
    mysql> insert t4 value('10.0.0.2',8080);
    mysql> insert t4 value('10.0.0.1',8080);
    ERROR 1062 (23000): Duplicate entry '10.0.0.1        -8080' for key 'ip'
        
    #例,单列主键
    mysql> create table t5(id int primary key);
    mysql> desc t5;
    +-------+---------+------+-----+---------+-------+
    | Field | Type    | Null | Key | Default | Extra |
    +-------+---------+------+-----+---------+-------+
    | id    | int(11) | NO   | PRI | NULL    |       |
    +-------+---------+------+-----+---------+-------+
    mysql> insert t5 value(1);
    mysql> insert t5 value(null);
    ERROR 1048 (23000): Column 'id' cannot be null
    mysql> insert t5 value(1);
    ERROR 1062 (23000): Duplicate entry '1' for key 'PRIMARY'
        
    #例,升级主键
    mysql> create table t6(id int not null unique,name varchar(4));
    mysql> desc t6;
    +-------+------------+------+-----+---------+-------+
    | Field | Type       | Null | Key | Default | Extra |
    +-------+------------+------+-----+---------+-------+
    | id    | int(11)    | NO   | PRI | NULL    |       |
    | name  | varchar(4) | YES  |     | NULL    |       |
    +-------+------------+------+-----+---------+-------+
    
    #例,联合主键
    mysql> create table t7(ip varchar(16),port int,primary key(ip,port));
    mysql> desc t7;
    +-------+-------------+------+-----+---------+-------+
    | Field | Type        | Null | Key | Default | Extra |
    +-------+-------------+------+-----+---------+-------+
    | ip    | varchar(16) | NO   | PRI |         |       |
    | port  | int(11)     | NO   | PRI | 0       |       |
    +-------+-------------+------+-----+---------+-------+
    
    #例,自增
    	#主键设置自增
    mysql> create table t8(id int primary key auto_increment,name varchar(4));
    mysql> desc t8;
    +-------+------------+------+-----+---------+----------------+
    | Field | Type       | Null | Key | Default | Extra          |
    +-------+------------+------+-----+---------+----------------+
    | id    | int(11)    | NO   | PRI | NULL    | auto_increment |
    | name  | varchar(4) | YES  |     | NULL    |                |
    +-------+------------+------+-----+---------+----------------+
    mysql> insert t8(name) value('syy'),('yyy');
    mysql> select * from t8;
    +----+------+
    | id | name |
    +----+------+
    |  1 | syy  |
    |  2 | yyy  |
    +----+------+
    mysql> delete from t8;		#清空表数据,不会重置主键
    mysql> insert t8(name) value('zyy');
    mysql> select * from t8;
    +----+------+
    | id | name |
    +----+------+
    |  3 | zyy  |
    +----+------+
    mysql> truncate t8;			#清空表数据和表结构,会重置主键
    mysql> insert t8(name) value('xyy');
    mysql> select * from t8;
    +----+------+
    | id | name |
    +----+------+
    |  1 | xyy  |
    +----+------+
    	#唯一键设置自增
    mysql> create table t9(id int unique auto_increment);
    mysql> desc t9;
    +-------+---------+------+-----+---------+----------------+
    | Field | Type    | Null | Key | Default | Extra          |
    +-------+---------+------+-----+---------+----------------+
    | id    | int(11) | NO   | PRI | NULL    | auto_increment |
    +-------+---------+------+-----+---------+----------------+
    mysql> insert t9 value(),(),();
    mysql> select * from t9;
    +----+
    | id |
    +----+
    |  1 |
    |  2 |
    |  3 |
    +----+
    

    表与表之间的关系(外键)

    #员工表
    id	emp_name	emp_gender	dep_name	dep_desc
    1	jason	male	外交部	形象代言人
    2	egon	female	教学部	教书育人
    3	tank	male	教学部	教书育人
    4	jerry	female	教学部	教书育人
    5	kevin	male	技术部	技术能力有限
    
    #所有信息都记录在一张表所带来的的问题
    	1.表的结构不清晰
        2.重复数据较多,代码冗余,浪费硬盘空间
        3.表的扩展性差
       
    #拆表,员工表
    id	emp_name	emp_gender	dep_id
    1	jason	male			1
    2	egon	female			2
    3	tank	male			2
    4	jerry	female			2
    5	kevin	male			3
    
    #拆表,部门表
    id	dep_name	dep_desc
    1	外交部		  形象代言人
    2	教学部		  教书育人
    3	技术部		  技术能力有限
    
    #判断表与表之间的关系
    	使用换位思考的方法
        数据的多对一,既是一对多,通常只说一对多
        查找表之间的关系,一定要站在两个表的角度考虑
        #员工到部门是多对一,部门到员工不是多对一,员工和部门是单向的多对一,单向的多对一/一对多统称一对多关系(等于多对一表关系)
        两表之间的关系字段,称为外键字段,一对多的外键字段建在多的一方,多对多的外键字段建在第三张表,一对一的外键字段建在任意一方都可以,但是推荐建在查询频率较高的一方
        
    #外键,foreign key,外键约束
    	外键就是两张表在代码层面上真正的关联
        #在创建外键的时候,必须先创建被关联表,再创建关联表(即外键表)
        #外键虽然能建立表关系,但同时也会增加数据相关的约束,造成被关联表的数据无法直接被修改
        #外键通常都设置级联更新、级联删除
        
    #表与表之间的关系只有三种,所以外键有三种
        一对一,图书与出版社
        一对多,部署与作者
        多对多,作者与作者详情
        
    #表关系的判断方法
    	判断表A的一条数据能否对应表B的多条数据
        	1.能
            	判断表B的一条数据能否对应表A的多条数据
                	1.能,两表之间的关系是'多对多'
                    2.不能,两表之间的关系是'一对多'
            2.不能
            	判断表B的一条数据能否对应表A的一条数据
            		1.能,两表之间的关系是'一对一'
                    2.不能,两表之间没有关系
    

    一对多

    #创建外键
    	#先创建被关联表
    mysql> create table dep(id int primary key auto_increment,dep_name varchar(32),dep_desc varchar(128));
    	#再创建关联表
    mysql> create table emp(id int primary key auto_increment,emp_name varchar(64),emp_gender enum('male','female'),dep_id int,foreign key(dep_id) references dep(id));
    mysql> desc emp;
    +------------+-----------------------+------+-----+---------+----------------+
    | Field      | Type                  | Null | Key | Default | Extra          |
    +------------+-----------------------+------+-----+---------+----------------+
    | id         | int(11)               | NO   | PRI | NULL    | auto_increment |
    | emp_name   | varchar(64)           | YES  |     | NULL    |                |
    | emp_gender | enum('male','female') | YES  |     | NULL    |                |
    | dep_id     | int(11)               | YES  | MUL | NULL    |                |
    +------------+-----------------------+------+-----+---------+----------------+
    mysql> desc dep;
    +----------+--------------+------+-----+---------+----------------+
    | Field    | Type         | Null | Key | Default | Extra          |
    +----------+--------------+------+-----+---------+----------------+
    | id       | int(11)      | NO   | PRI | NULL    | auto_increment |
    | dep_name | varchar(32)  | YES  |     | NULL    |                |
    | dep_desc | varchar(128) | YES  |     | NULL    |                |
    +----------+--------------+------+-----+---------+----------------+
        #先插入被关联表数据
    mysql> insert dep(dep_name,dep_desc) values('外交部','搞外交'),('教学部','教书育人'),('技术部','技术能力有限');
        #再插入关联表数据
    mysql> insert emp(emp_name,dep_id) values('jason',1),('egon',2),('tank',2),('kevin',3);
    mysql> select * from emp;
    +----+----------+------------+--------+
    | id | emp_name | emp_gender | dep_id |
    +----+----------+------------+--------+
    |  1 | jason    | NULL       |      1 |
    |  2 | egon     | NULL       |      2 |
    |  3 | tank     | NULL       |      2 |
    |  4 | kevin    | NULL       |      3 |
    +----+----------+------------+--------+
    mysql> select * from dep;
    +----+-----------+--------------------+
    | id | dep_name  | dep_desc           |
    +----+-----------+--------------------+
    |  1 | 外交部    | 搞外交             |
    |  2 | 教学部    | 教书育人           |
    |  3 | 技术部    | 技术能力有限       |
    +----+-----------+--------------------+
       #修改表数据 
    mysql> update dep set id=100 where id=1;
    ERROR 1451 (23000): Cannot delete or update a parent row: a foreign key constraint fails (`test`.`emp`, CONSTRAINT `emp_ibfk_1` FOREIGN KEY (`dep_id`) REFERENCES `dep` (`id`))
    mysql> update emp set dep_id=100 where id=1;
    ERROR 1452 (23000): Cannot add or update a child row: a foreign key constraint fails (`test`.`emp`, CONSTRAINT `emp_ibfk_1` FOREIGN KEY (`dep_id`) REFERENCES `dep` (`id`))
       #删除表数据
    mysql> delete from dep where id=1;
    ERROR 1451 (23000): Cannot delete or update a parent row: a foreign key constraint fails (`test`.`emp`, CONSTRAINT `emp_ibfk_1` FOREIGN KEY (`dep_id`) REFERENCES `dep` (`id`))
       #删除表
    mysql> drop table emp;
    mysql> drop table dep;
            
    #外键的级联更新、级联删除
    	#先创建被关联表
    mysql> create table dep(id int primary key auto_increment,dep_name varchar(32),dep_desc varchar(128));
    	#再创建关联表
    mysql> create table emp(id int primary key auto_increment,emp_name varchar(64),emp_gender enum('male','female'),dep_id int,foreign key(dep_id) references dep(id) on update cascade on delete cascade);
        #先插入被关联表数据
    mysql> insert dep(dep_name,dep_desc) values('外交部','搞外交'),('教学部','教书育人'),('技术部','技术能力有限');
        #再插入关联表数据
    mysql> insert emp(emp_name,dep_id) values('jason',1),('egon',2),('tank',2),('kevin',3);
    mysql> select * from emp;
    +----+----------+------------+--------+
    | id | emp_name | emp_gender | dep_id |
    +----+----------+------------+--------+
    |  1 | jason    | NULL       |      1 |
    |  2 | egon     | NULL       |      2 |
    |  3 | tank     | NULL       |      2 |
    |  4 | kevin    | NULL       |      3 |
    +----+----------+------------+--------+
    mysql> select * from dep;
    +----+-----------+--------------------+
    | id | dep_name  | dep_desc           |
    +----+-----------+--------------------+
    |  1 | 外交部    | 搞外交             |
    |  2 | 教学部    | 教书育人           |
    |  3 | 技术部    | 技术能力有限       |
    +----+-----------+--------------------+
    	#修改表数据
    mysql> update dep set id=200 where id=3;
    mysql> select * from dep;
    +-----+-----------+--------------------+
    | id  | dep_name  | dep_desc           |
    +-----+-----------+--------------------+
    |   1 | 外交部    | 搞外交             |
    |   2 | 教学部    | 教书育人           |
    | 200 | 技术部    | 技术能力有限       |
    +-----+-----------+--------------------+
    mysql> select * from emp;
    +----+----------+------------+--------+
    | id | emp_name | emp_gender | dep_id |
    +----+----------+------------+--------+
    |  1 | jason    | NULL       |      1 |
    |  2 | egon     | NULL       |      2 |
    |  3 | tank     | NULL       |      2 |
    |  4 | kevin    | NULL       |    200 |
    +----+----------+------------+--------+
    
    	#删除表数据
    mysql> delete from dep where id=2;
    mysql> select * from dep;
    +-----+-----------+--------------------+
    | id  | dep_name  | dep_desc           |
    +-----+-----------+--------------------+
    |   1 | 外交部    | 搞外交             |
    | 200 | 技术部    | 技术能力有限       |
    +-----+-----------+--------------------+
    mysql> select * from emp;
    +----+----------+------------+--------+
    | id | emp_name | emp_gender | dep_id |
    +----+----------+------------+--------+
    |  1 | jason    | NULL       |      1 |
    |  4 | kevin    | NULL       |    200 |
    +----+----------+------------+--------+
    

    多对多

    #book
    id	title	price	desc	
    1	jpm     888.88	不可描述
    2	python	22222	变成屌丝
    3	聊斋	999.99	魔幻世界
    
    #author
    id	name	age	
    1	jason	18
    2	egon	66
    
    #书籍和作者的关系是多对一,作者和书籍的关系也是多对一,两张表之间是多对多的关系
    	多对多关系的建立,必须手动创建第三张表,用来专门记录两张表之间的关系
    	
        #先创建两张普通的表,不设置外键
    mysql> create table book(id int primary key auto_increment,title varchar(32),price int);
    mysql> create table author(id int primary key auto_increment,name varchar(32),age int);
    	#再创建第三张表,设置外键
    mysql> create table book_author(id int primary key auto_increment,book_id int,foreign key(book_id) references book(id) on update cascade on delete cascade,author_id int,foreign key(author_id) references author(id) on update cascade on delete cascade);
    	#查看表结构
    mysql> desc book;
    +-------+-------------+------+-----+---------+----------------+
    | Field | Type        | Null | Key | Default | Extra          |
    +-------+-------------+------+-----+---------+----------------+
    | id    | int(11)     | NO   | PRI | NULL    | auto_increment |
    | title | varchar(32) | YES  |     | NULL    |                |
    | price | int(11)     | YES  |     | NULL    |                |
    +-------+-------------+------+-----+---------+----------------+
    mysql> desc author;
    +-------+-------------+------+-----+---------+----------------+
    | Field | Type        | Null | Key | Default | Extra          |
    +-------+-------------+------+-----+---------+----------------+
    | id    | int(11)     | NO   | PRI | NULL    | auto_increment |
    | name  | varchar(32) | YES  |     | NULL    |                |
    | age   | int(11)     | YES  |     | NULL    |                |
    +-------+-------------+------+-----+---------+----------------+
    mysql> desc book_author;
    +-----------+---------+------+-----+---------+----------------+
    | Field     | Type    | Null | Key | Default | Extra          |
    +-----------+---------+------+-----+---------+----------------+
    | id        | int(11) | NO   | PRI | NULL    | auto_increment |
    | book_id   | int(11) | YES  | MUL | NULL    |                |
    | author_id | int(11) | YES  | MUL | NULL    |                |
    +-----------+---------+------+-----+---------+----------------+
    	#插入数据
    mysql> insert book(title,price) values('jpm',199),('聊斋',299),('鸡神',999);
    mysql> insert author(name,age) values('jason',18),('tank',88);
    mysql> insert book_author(book_id,author_id) values(1,1),(1,2),(2,1),(3,1),(3,2);
    mysql> select * from book;
    +----+-----------+-------+
    | id | title     | price |
    +----+-----------+-------+
    |  1 | jpm       |   199 |
    |  2 | 聊斋      |   299 |
    |  3 | 鸡神      |   999 |
    +----+-----------+-------+
    mysql> select * from author;
    +----+-------+------+
    | id | name  | age  |
    +----+-------+------+
    |  1 | jason |   18 |
    |  2 | tank  |   88 |
    +----+-------+------+
    mysql> select * from book_author;
    +----+---------+-----------+
    | id | book_id | author_id |
    +----+---------+-----------+
    |  1 |       1 |         1 |
    |  2 |       1 |         2 |
    |  3 |       2 |         1 |
    |  4 |       3 |         1 |
    |  5 |       3 |         2 |
    +----+---------+-----------+
    	#删除表数据
    mysql> delete from author where id=1;
    mysql> select * from book;
    +----+-----------+-------+
    | id | title     | price |
    +----+-----------+-------+
    |  1 | jpm       |   199 |
    |  2 | 聊斋      |   299 |
    |  3 | 鸡神      |   999 |
    +----+-----------+-------+
    mysql> select * from author;
    +----+------+------+
    | id | name | age  |
    +----+------+------+
    |  2 | tank |   88 |
    +----+------+------+
    mysql> select * from book_author;
    +----+---------+-----------+
    | id | book_id | author_id |
    +----+---------+-----------+
    |  2 |       1 |         2 |
    |  5 |       3 |         2 |
    +----+---------+-----------+
    

    一对一

    #一对一
    	一个表中的数据,跟另外一张表中的数据是一一对应的
        #一对一表关系跟一对多表关系的语法结构完全一致,只不过需要给外键字段在加一个unique唯一性约束即可
    
    #一对一应用场景1
    	#当表特别大的时候可以考虑拆分表,比如qq界面的用户名和其他信息,作者与作者详情
        
    author		
    id	name	age	  authordetail_id
    1	xxx		18		1
    		
    authordetail		
    phone	addr
    111		xxx
        
    #一对一应用场景2
    	#招生咨询和学生
    id	name	qq	course
    1	小林	111	python
    2	小红	222	C
    3	小芳	333	python
    4	小黄	444	java
    
    id	name	course
    1	小林	python
    2	小芳	python
     
        
    #例,场景1代码实现
    	#先创建被关联表
    mysql> create table authordetail(id int primary key auto_increment,phone int,addr char(255));
    	#再创建外键表
    mysql> create table author(id int primary key auto_increment,name char(4),age int,authordetail_id int unique,foreign key(authordetail_id) references authordetail(id) on update cascade on delete cascade); 
    	#查看表结构
    mysql> desc author;
    +-----------------+---------+------+-----+---------+----------------+
    | Field           | Type    | Null | Key | Default | Extra          |
    +-----------------+---------+------+-----+---------+----------------+
    | id              | int(11) | NO   | PRI | NULL    | auto_increment |
    | name            | char(4) | YES  |     | NULL    |                |
    | age             | int(11) | YES  |     | NULL    |                |
    | authordetail_id | int(11) | YES  | UNI | NULL    |                |
    +-----------------+---------+------+-----+---------+----------------+
    mysql> desc authordetail;
    +-------+-----------+------+-----+---------+----------------+
    | Field | Type      | Null | Key | Default | Extra          |
    +-------+-----------+------+-----+---------+----------------+
    | id    | int(11)   | NO   | PRI | NULL    | auto_increment |
    | phone | int(11)   | YES  |     | NULL    |                |
    | addr  | char(255) | YES  |     | NULL    |                |
    +-------+-----------+------+-----+---------+----------------+
    	#插入表数据,先插入被关联表,再插入外键表
    mysql> insert authordetail(phone,addr) values(110,'china'),(120,'USA'),(130,'Ac');
    mysql> insert author(name,age,authordetail_id) values('jaso',18,1),('egon',88,2);
    mysql> select * from author;
    +----+------+------+-----------------+
    | id | name | age  | authordetail_id |
    +----+------+------+-----------------+
    |  1 | jaso |   18 |               1 |
    |  2 | egon |   88 |               2 |
    +----+------+------+-----------------+
    mysql> select * from authordetail;
    | id | phone | addr                                                             
    |  1 |   110 | china                                                           
    |  2 |   120 | USA                                                             
    |  3 |   130 | Ac                                                               
    

    SQL语句补充

    alter

    #修改表名
    	alter table 表名 rename 新表名;
        
    #增加字段
    	alter table 表名 add 字段名 数据类型 [约束条件],
        				add 字段名 数据类型 [约束条件];
    	alter table 表名 add 字段名 数据类型 [约束条件] first;
    	alter table 表名 add 字段名 数据类型 [约束条件] after 字段名;	
    
    #删除字段
    	alter table 表名 drop 字段名;
        
    #修改字段
    	#modify只能修改字段类型约束条件,不能修改字段名,但是change都可以
    	alter table 表名 modify 字段名 数据类型 [约束条件];
        alter table 表名 change 旧字段名 新字段名 数据类型 [约束条件];
        
    #SQL语句后面加上G,可以将要查看的表中的数据竖向排列
    

    复制表

    #使用select查询,结果也是一张表,可以看成虚拟表
    #复制表
    	#注意,该方法只会复制表结构和表数据,不会复制主键、唯一键、外键、索引
    create table 新表名 select * from 旧表名;
    
    #只复制表结构
    select * from 旧表名 where 1=2;		#因为条件为假,所以查不到任何表数据
    create table 新表名 select * from 旧表名 where 1=2;
    
    create table 新表名 like 旧表名;
    

    单表查询

    where子句

    #SQL语句的执行顺序
    	#客户端发送SQL语句到mysql服务端
    		mysql> select id,name from emp where id>3 and id<6;
        #服务端执行SQL语句
            from		#从哪张表拿数据
            where		#筛选数据,一条一条的
            group by	#指定分组,默认一个表就是一组
            having		#筛选数据,一条一条的
            select		#筛选数据,一个字段一个字段的
            distinct	#去重
        #返回结果给客户端
    
    #创建表
    mysql> create table emp(
        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 18,
        hire_date date not null,		#雇佣日期
        post varchar(50),				#岗位
        post_comment varchar(100),		#岗位描述
        salary double(15,2),			#薪水
        office int,						#部门
        depart_id int					#id
    );
    mysql> desc emp;
    +--------------+-----------------+------+-----+---------+----------------+
    | Field        | Type                  | Null | Key | Default | Extra          |
    +--------------+-----------------+------+-----+---------+----------------+
    | id           | int(11)               | NO   | PRI | NULL    | auto_increment |
    | name         | varchar(20)           | NO   |     | NULL    |                |
    | sex          | enum('male','female') | NO   |     | male    |                |
    | age          | int(3) unsigned       | NO   |     | 18      |                |
    | hire_date    | date                  | NO   |     | NULL    |                |
    | post         | varchar(50)           | YES  |     | NULL    |                |
    | post_comment | varchar(100)          | YES  |     | NULL    |                |
    | salary       | double(15,2)          | YES  |     | NULL    |                |
    | office       | int(11)               | YES  |     | NULL    |                |
    | depart_id    | int(11)               | YES  |     | NULL    |                |
    +--------------+-----------------+------+-----+---------+----------------+
    	#插入数据
        #ps,如果在Windows系统中,插入中文字符,select的结果为空白的话,可以将所有字符编码统一设置为'gbk'
    insert emp(name,sex,age,hire_date,post,salary,office,depart_id) values
    ('aa','male',77,'20120101','teacher',10.100,401,1),	#教学部
    ('bb','male',66,'20120201','teacher',9.99,401,1),
    ('cc','female',55,'20120301','teacher',8.98,401,1),
    ('dd','male',44,'20120401','teacher',7.97,401,1),
    ('ee','male',33,'20120501','teacher',6.96,401,1),
    ('ff','female',22,'20120601','teacher',5.95,401,1),
        
    ('gg','male',18,'20100101','sale',4.94,402,2),	#销售部
    ('hh','male',19,'20100201','sale',3.93,402,2),
    ('ii','male',20,'20100301','sale',2.92,402,2),
    ('jj','male',21,'20100401','sale',1.91,402,2),
    ('kk','male',22,'20100501','sale',0.90,402,2),
        
    ('ll','male',23,'20200101','operation',4.89,403,3),	#运营部
    ('mm','male',24,'20200201','operation',3.88,403,3),
    ('nn','male',25,'20200301','operation',2.87,403,3),
    ('oo','male',26,'20200401','operation',1.86,403,3),
    ('pp','male',27,'20200501','operation',0.85,403,3);
    
    #1.查询id大于等于3小于等于6的数据
    mysql> select * from emp where id >=3 and id <=6;
    mysql> select * from emp where id between 3 and 6;
    #2.查询薪资是2.92或者1.91或者0.90的数据
    mysql> select * from emp where salary=2.92 or salary=1.91 or salary=0.90;
    mysql> select * from emp where salary in (2.87,1.86,0.85);
    #3.查询员工姓名中,包含o字母的员工姓名和薪资
    mysql> select name,salary from emp where name like '%o%';
    #4.查询员工姓名是由两个字符组成的员工姓名和薪资
    mysql> select name,salary from emp where name like '__';
    mysql> select name,salary from emp where char_length(name)=4;
    #5.查询id小于3或者大于6的数据
    mysql> select * from emp where id<3 or id>6;
    mysql> select * from emp where id not between 3 and 6;
    #6.查询薪资不是2.92或者1.91或者0.90的数据
    mysql> select * from emp where salary not in (2.87,1.86,0.85);
    #7.查询岗位描述为空的员工与岗位名(针对null不能用等号,只能用is)
    mysql> select name,post from emp where post_comment = NULL;			#错
    mysql> select name,post from emp where post_comment is NULL;		
    mysql> select name,post from emp where post_comment is not NULL;
    

    group by

    #group by,分组
    	#分组之后,查询数据的最小单位是组,不会再默认展示组内的单条数据
        #mysql中,分组之后只能查看分组的字段信息,无法直接获取其他的字段信息,但是可以通过其他的方法(聚合函数)间接的获取
        #聚合函数有:max()、min()、avg()、sum()、count()、group_concat()
            #聚合函数只能在SQL语句group by分组之后使用
            #如果SQL没有分组,那么默认该表内的所有数据就是一组,所以仍可以使用所有的聚合函数(max,min,avg,sum,count,group_caoncat)
    
    #1.按部门分组
    mysql> select * from emp group by post;		
    	#如果设置SQL严格模式,该语句报错,不设置的话不报错
    	#使用post对数据分组,默认显示每组的第一条数据
    +----+------+----+-----------+--------------+--------+--------+-----------+
    | id | name | sex  | age | hire_date  | post      | post_comment | salary | office | depart_id |
    +----+------+----+-----------+--------------+--------+--------+-----------+
    | 12 | ll   | male |  23 | 2020-01-01 | operation | NULL         |   4.89 |    403 |         3 |
    |  7 | gg   | male |  18 | 2010-01-01 | sale      | NULL         |   4.94 |    402 |         2 |
    |  1 | aa   | male |  77 | 2012-01-01 | teacher   | NULL         |  10.10 |    401 |         1 |
    +----+------+----+-----------+--------------+--------+--------+-----------+
    	#查看SQL严格模式是否开启
    mysql> show variables like '%mode%';
    	#设置SQL严格模式
    mysql> set session sql_mode='STRICT_TRANS_TABLES,only_full_group_by';
    mysql> set global sql_mode='STRICT_TRANS_TABLES,only_full_group_by';
    	#直接报错,这个时候只能查看分组字段数据
    mysql> select * from emp group by post;
    ERROR 1055 (42000): 'z6.emp.id' isn't in GROUP BY
    mysql> select post from emp group by post;
    +-----------+
    | post      |
    +-----------+
    | operation |
    | sale      |
    | teacher   |
    +-----------+
    #2.获取每个部门的最高薪资
    mysql> select post,max(salary) from emp group by post;
    +-----------+-------------+
    | post      | max(salary) |
    +-----------+-------------+
    | operation |        4.89 |
    | sale      |        4.94 |
    | teacher   |       10.10 |
    +-----------+-------------+
    	#使用关键字as,给虚拟表字段起别名(as可以可以省略)
    mysql> select post as '部门',max(salary) as '最高薪资' from emp group by post;
    mysql> select post '部门',max(salary) '最高薪资' from emp group by post;
    +-----------+--------------+
    | 部门      | 最高薪资     |
    +-----------+--------------+
    | operation |         4.89 |
    | sale      |         4.94 |
    | teacher   |        10.10 |
    +-----------+--------------+
    	#获取每个部门的最低薪资
    mysql> select post as '部门',min(salary) as '最低薪资' from emp group by post;
    +-----------+--------------+
    | 部门      | 最低薪资     |
    +-----------+--------------+
    | operation |         0.85 |
    | sale      |         0.90 |
    | teacher   |         5.95 |
    +-----------+--------------+
    	#获取每个部门的平均薪资
    mysql> select post as '部门',avg(salary) as '平均薪资' from emp group by post;
    +-----------+--------------+
    | 部门      | 平均薪资     |
    +-----------+--------------+
    | operation |     2.870000 |
    | sale      |     2.920000 |
    | teacher   |     8.325000 |
    +-----------+--------------+
    	#获取每个部门的薪资总和
    mysql> select post as '部门',sum(salary) as '薪资总和' from emp group by post;
    +-----------+--------------+
    | 部门      | 薪资总和     |
    +-----------+--------------+
    | operation |        14.35 |
    | sale      |        14.60 |
    | teacher   |        49.95 |
    	#获取每个部门的人数
        #在使用关键字count,统计分组内个数的时候,填写任意非空字段都可以完成计数,但是要使用唯一标识数据的字段(非空字段)
    mysql> select post as '部门',count(id) as '总人数' from emp group by post;
    +-----------+-----------+
    | 部门      | 总人数    |
    +-----------+-----------+
    | operation |         5 |
    | sale      |         5 |
    | teacher   |         6 |
    +-----------+-----------+
    #3.查询分组之后的部门名称和每个部门下所有的名字
    	#group_concat(分组之后用),不仅可以用来显示指定字段的数据,还有拼接字符串的作用
    mysql> select post,group_concat(name) from emp group by post;
    +-----------+--------------------+
    | post      | group_concat(name) |
    +-----------+--------------------+
    | operation | pp,oo,nn,mm,ll     |
    | sale      | kk,jj,ii,hh,gg     |
    | teacher   | ff,ee,dd,cc,bb,aa  |
    +-----------+--------------------+
    	#拼接字符串
    mysql> select post,group_concat(name,'_DSB') from emp group by post;
    +-----------+-------------------------------------------+
    | post      | group_concat(name,'_DSB')                 |
    +-----------+-------------------------------------------+
    | operation | pp_DSB,oo_DSB,nn_DSB,mm_DSB,ll_DSB        |
    | sale      | kk_DSB,jj_DSB,ii_DSB,hh_DSB,gg_DSB        |
    | teacher   | ff_DSB,ee_DSB,dd_DSB,cc_DSB,bb_DSB,aa_DSB |
    +-----------+-------------------------------------------+
    mysql> select post,group_concat(name,':',salary) from emp group by post;
    +-----------+--------------------------------------------------+
    | post      | group_concat(name,':',salary)                    |
    +-----------+--------------------------------------------------+
    | operation | pp:0.85,oo:1.86,nn:2.87,mm:3.88,ll:4.89          |
    | sale      | kk:0.90,jj:1.91,ii:2.92,hh:3.93,gg:4.94          |
    | teacher   | ff:5.95,ee:6.96,dd:7.97,cc:8.98,bb:9.99,aa:10.10 |
    +-----------+--------------------------------------------------+
    
    #4.concat(不分组时用),拼接字符串达到更好的显示效果
    mysql> select name as 姓名,salary as 薪资 from emp;
    +--------+--------+
    | 姓名   | 薪资   |
    +--------+--------+
    | aa     |  10.10 |
    | bb     |   9.99 |
    | cc     |   8.98 |
    | dd     |   7.97 |
    | ee     |   6.96 |
    | ff     |   5.95 |
    | gg     |   4.94 |
    | hh     |   3.93 |
    | ii     |   2.92 |
    | jj     |   1.91 |
    | kk     |   0.90 |
    | ll     |   4.89 |
    | mm     |   3.88 |
    | nn     |   2.87 |
    | oo     |   1.86 |
    | pp     |   0.85 |
    +--------+--------+
    mysql> select concat('name: ',name) as 姓名,concat('SAL: ',salary) as 薪资 from emp;
    +----------+------------+
    | 姓名     | 薪资       |
    +----------+------------+
    | name: aa | SAL: 10.10 |
    | name: bb | SAL: 9.99  |
    | name: cc | SAL: 8.98  |
    | name: dd | SAL: 7.97  |
    | name: ee | SAL: 6.96  |
    | name: ff | SAL: 5.95  |
    | name: gg | SAL: 4.94  |
    | name: hh | SAL: 3.93  |
    | name: ii | SAL: 2.92  |
    | name: jj | SAL: 1.91  |
    | name: kk | SAL: 0.90  |
    | name: ll | SAL: 4.89  |
    | name: mm | SAL: 3.88  |
    | name: nn | SAL: 2.87  |
    | name: oo | SAL: 1.86  |
    | name: pp | SAL: 0.85  |
    +----------+------------+
    #5.concat_ws(分组只有用),使用指定符号拼接数据
    mysql> select concat_ws(':',name,sex,age) from emp2;
    +-----------------------------+
    | concat_ws(':',name,sex,age) |
    +-----------------------------+
    | jason:male:18               |
    | egon:female:48              |
    | kevin:male:38               |
    | nick:female:28              |
    | jerry:female:18             |
    +-----------------------------+
    
    #补充
    	#as既可以给字段起别名,也可以给表起别名
    mysql> select emp.id,emp.name from emp as t1;
    ERROR 1054 (42S22): Unknown column 'emp.id' in 'field list'
    mysql> select t1.id,t1.name from emp as t1;
    +----+------+
    | id | name |
    +----+------+
    |  1 | aa   |
    |  2 | bb   |
    |  3 | cc   |
    |  4 | dd   |
    |  5 | ee   |
    |  6 | ff   |
    |  7 | gg   |
    |  8 | hh   |
    |  9 | ii   |
    | 10 | jj   |
    | 11 | kk   |
    | 12 | ll   |
    | 13 | mm   |
    | 14 | nn   |
    | 15 | oo   |
    | 16 | pp   |
    +----+------+
    	#查询之四则运算
    mysql> select name,salary*13 from emp;
    +------+-----------+
    | name | salary*13 |
    +------+-----------+
    | aa   |    131.30 |
    | bb   |    129.87 |
    | cc   |    116.74 |
    | dd   |    103.61 |
    | ee   |     90.48 |
    | ff   |     77.35 |
    | gg   |     64.22 |
    | hh   |     51.09 |
    | ii   |     37.96 |
    | jj   |     24.83 |
    | kk   |     11.70 |
    | ll   |     63.57 |
    | mm   |     50.44 |
    | nn   |     37.31 |
    | oo   |     24.18 |
    | pp   |     11.05 |
    +------+-----------+
    	#group by可以与where一起使用
    mysql> select post,group_concat(salary) from emp where id <5 group by post;
    +---------+----------------------+
    | post    | group_concat(salary) |
    +---------+----------------------+
    | teacher | 10.10,9.99,8.98,7.97 |
    +---------+----------------------+
    	#聚合函数只能在group by之后使用,因为post不是分组依据,所以报错
    mysql> select post,max(salary) from emp;
    ERROR 1140 (42000): Mixing of GROUP columns (MIN(),MAX(),COUNT(),...) with no GROUP columns is illegal if there is no GROUP BY clause
        #因为整个表默认就是一组,所以仍可以使用所有聚合函数
    mysql> select max(salary) from emp;
    +-------------+
    | max(salary) |
    +-------------+
    |       10.10 |
    +-------------+
    

    练习题

    #刚开始查询表,一定要按照最基本的步骤
    	1.先确定是哪张表
        2.再确定这张表有没有限制条件(where)
        3.再确定是否需要分类(xx下,xx中,xx内,xx包含的,各xx)
        4.最后再确定需要什么字段对应的信息
        
    #1.查询岗位名以及岗位包含的所有员工的名字
    mysql> select post,group_concat(name) from emp group by post;
    +-----------+--------------------+
    | post      | group_concat(name) |
    +-----------+--------------------+
    | operation | pp,oo,nn,mm,ll     |
    | sale      | kk,jj,ii,hh,gg     |
    | teacher   | ff,ee,dd,cc,bb,aa  |
    +-----------+--------------------+
    #2.查询岗位名以及各岗位内包含的员工的个数
    mysql> select post,count(id) from emp group by post;
    +-----------+-----------+
    | post      | count(id) |
    +-----------+-----------+
    | operation |         5 |
    | sale      |         5 |
    | teacher   |         6 |
    +-----------+-----------+
    #3.查询公司内男员工和女员工的个数
    mysql> select sex,count(id) from emp group by sex;
    +--------+-----------+
    | sex    | count(id) |
    +--------+-----------+
    | male   |        14 |
    | female |         2 |
    +--------+-----------+
    #4.查询岗位名以及各岗位的平均薪资
    mysql> select post,avg(salary) from emp group by post;
    +-----------+-------------+
    | post      | avg(salary) |
    +-----------+-------------+
    | operation |    2.870000 |
    | sale      |    2.920000 |
    | teacher   |    8.325000 |
    +-----------+-------------+
    #5.查询岗位名以及各岗位的最高薪资
    mysql> select post,max(salary) from emp group by post;
    +-----------+-------------+
    | post      | max(salary) |
    +-----------+-------------+
    | operation |        4.89 |
    | sale      |        4.94 |
    | teacher   |       10.10 |
    +-----------+-------------+
    #6.查询岗位名以及各岗位的最低薪资
    mysql> select post,min(salary) from emp group by post;
    +-----------+-------------+
    | post      | min(salary) |
    +-----------+-------------+
    | operation |        0.85 |
    | sale      |        0.90 |
    | teacher   |        5.95 |
    +-----------+-------------+
    #7.查询男员工和女员工的平均薪资,女员工与女员工的平均薪资
    mysql> select sex,avg(salary) from emp group by sex;
    +--------+-------------+
    | sex    | avg(salary) |
    +--------+-------------+
    | male   |    4.569286 |
    | female |    7.465000 |
    +--------+-------------+
    #8.查询各部门年龄在30岁以上的员工的平均工资
    mysql> select post,avg(salary) from emp where age >= 30 group by post;
    +---------+-------------+
    | post    | avg(salary) |
    +---------+-------------+
    | teacher |    8.800000 |
    +---------+-------------+
    
    

    having

    #having
    	having跟where的作用是一模一样的,都是用来筛选数据的
        where在简单的SQL语句中可以直接使用,但是不能在复杂的SQL语句中使用,如group by之后
        如果想要在group by之后,再次对数据进行筛选,只能使用关键字having
        having只能在group by之后使用
        
    1.查询各部门年龄在30岁以上的员工的平均工资,并且保留平均薪资大于8的部门
    mysql> insert emp(name,sex,age,hire_date,post,salary,office,depart_id) values('xx','female',31,'20120101','other',1,401,10);
    mysql> select post,avg(salary) from emp where age >= 30 group by post;
    +---------+-------------+
    | post    | avg(salary) |
    +---------+-------------+
    | other   |    1.000000 |
    | teacher |    8.800000 |
    +---------+-------------+
    2 rows in set (0.00 sec)
    
    mysql> select post,avg(salary) from emp where age >= 30 group by post having avg(salary)>8;
    +---------+-------------+
    | post    | avg(salary) |
    +---------+-------------+
    | teacher |    8.800000 |
    +---------+-------------+
    

    distinct

    #distinct去重
        两条数据必须是一模一样,才能使用关键字distinct去重
    	对重复展示的数据进行去重,保留一条
        distinct必须紧跟在select之后,鉴于SQL语句的执行步骤 
        
    #例
    mysql> select sex from emp;
    +--------+
    | sex    |
    +--------+
    | male   |
    | male   |
    | female |
    | male   |
    | male   |
    | female |
    | male   |
    | male   |
    | male   |
    | male   |
    | male   |
    | male   |
    | male   |
    | male   |
    | male   |
    | male   |
    | female |
    +--------+
    17 rows in set (0.00 sec)
    
    mysql> select distinct sex from emp;
    +--------+
    | sex    |
    +--------+
    | male   |
    | female |
    +--------+
    

    order by

    #order by,排序
    	order by 		升序,默认,asc
        order by desc 	降序,desc
        
    #例
    	#升序
    mysql> select id,name,salary from emp order by salary;
    mysql> select id,name,salary from emp order by salary asc;
    +----+------+--------+
    | id | name | salary |
    +----+------+--------+
    | 16 | pp   |   0.85 |
    | 11 | kk   |   0.90 |
    | 19 | xx   |   1.00 |
    | 15 | oo   |   1.86 |
    | 10 | jj   |   1.91 |
    | 14 | nn   |   2.87 |
    |  9 | ii   |   2.92 |
    | 13 | mm   |   3.88 |
    |  8 | hh   |   3.93 |
    | 12 | ll   |   4.89 |
    |  7 | gg   |   4.94 |
    |  6 | ff   |   5.95 |
    |  5 | ee   |   6.96 |
    |  4 | dd   |   7.97 |
    |  3 | cc   |   8.98 |
    |  2 | bb   |   9.99 |
    |  1 | aa   |  10.10 |
    +----+------+--------+
    	#降序
    mysql> select id,name,salary from emp order by salary desc;
    +----+------+--------+
    | id | name | salary |
    +----+------+--------+
    |  1 | aa   |  10.10 |
    |  2 | bb   |   9.99 |
    |  3 | cc   |   8.98 |
    |  4 | dd   |   7.97 |
    |  5 | ee   |   6.96 |
    |  6 | ff   |   5.95 |
    |  7 | gg   |   4.94 |
    | 12 | ll   |   4.89 |
    |  8 | hh   |   3.93 |
    | 13 | mm   |   3.88 |
    |  9 | ii   |   2.92 |
    | 14 | nn   |   2.87 |
    | 10 | jj   |   1.91 |
    | 15 | oo   |   1.86 |
    | 19 | xx   |   1.00 |
    | 11 | kk   |   0.90 |
    | 16 | pp   |   0.85 |
    +----+------+--------+
    	#先比较age字段(升序),对于age字段相同的数据,再比较salary字段(升序)
    mysql> select id,name,age,salary from emp order by age,salary;
    +----+------+-----+--------+
    | id | name | age | salary |
    +----+------+-----+--------+
    |  7 | gg   |  18 |   4.94 |
    |  8 | hh   |  19 |   3.93 |
    |  9 | ii   |  20 |   2.92 |
    | 10 | jj   |  21 |   1.91 |
    | 11 | kk   |  22 |   0.90 |	#
    |  6 | ff   |  22 |   5.95 |
    | 12 | ll   |  23 |   4.89 |
    | 13 | mm   |  24 |   3.88 |
    | 14 | nn   |  25 |   2.87 |
    | 15 | oo   |  26 |   1.86 |
    | 16 | pp   |  27 |   0.85 |
    | 19 | xx   |  31 |   1.00 |
    |  5 | ee   |  33 |   6.96 |
    |  4 | dd   |  44 |   7.97 |
    |  3 | cc   |  55 |   8.98 |
    |  2 | bb   |  66 |   9.99 |
    |  1 | aa   |  77 |  10.10 |
    +----+------+-----+--------+
    	#先比较age字段(升序),对于age字段相同的数据,再比较salary字段(降序)
    mysql> select id,name,age,salary from emp order by age asc,salary desc;
    +----+------+-----+--------+
    | id | name | age | salary |
    +----+------+-----+--------+
    |  7 | gg   |  18 |   4.94 |
    |  8 | hh   |  19 |   3.93 |
    |  9 | ii   |  20 |   2.92 |
    | 10 | jj   |  21 |   1.91 |
    |  6 | ff   |  22 |   5.95 |	#
    | 11 | kk   |  22 |   0.90 |
    | 12 | ll   |  23 |   4.89 |
    | 13 | mm   |  24 |   3.88 |
    | 14 | nn   |  25 |   2.87 |
    | 15 | oo   |  26 |   1.86 |
    | 16 | pp   |  27 |   0.85 |
    | 19 | xx   |  31 |   1.00 |
    |  5 | ee   |  33 |   6.96 |
    |  4 | dd   |  44 |   7.97 |
    |  3 | cc   |  55 |   8.98 |
    |  2 | bb   |  66 |   9.99 |
    |  1 | aa   |  77 |  10.10 |
    +----+------+-----+--------+
    
    #例,统计各部门年龄在10岁以上的员工的平均工资,并且保留平均工资大于0.9的部门,然后对平均工资进行排序
    mysql> select post,avg(salary) from emp where age >10 group by post having avg(salary)>0.9 order by avg(salary);
    +-----------+-------------+
    | post      | avg(salary) |
    +-----------+-------------+
    | other     |    1.000000 |
    | operation |    2.870000 |
    | sale      |    2.920000 |
    | teacher   |    8.325000 |
    +-----------+-------------+
    

    limit

    #limit
    	#限制展示数据的条数
        #使用场景,分页
        
    #例
    mysql> select id,name from emp limit 5;
    +----+------+
    | id | name |
    +----+------+
    |  1 | aa   |
    |  2 | bb   |
    |  3 | cc   |
    |  4 | dd   |
    |  5 | ee   |
    +----+------+
    	#limit(x,y),x表示起始位置(不包括起始位置),y表示要展示数据的条数,
    mysql> select id,name from emp limit 0,2;
    +----+------+
    | id | name |
    +----+------+
    |  1 | aa   |
    |  2 | bb   |
    +----+------+
    mysql> select id,name from emp limit 2,2;
    +----+------+
    | id | name |
    +----+------+
    |  3 | cc   |
    |  4 | dd   |
    +----+------+
    
    	#查询工资最高的人的详细信息
    mysql> select * from emp order by salary limit 1;
    +----+------+----+-----------+--------------+--------+--------+-----------+
    | id | name | sex  | age | hire_date  | post      | post_comment | salary | office | depart_id |
    +----+------+----+-----------+--------------+--------+--------+-----------+
    | 16 | pp   | male |  27 | 2020-05-01 | operation | NULL         |   0.85 |    403 |         3 |
    +----+------+----+-----------+--------------+--------+--------+-----------+
    
    

    正则

    #在编程中,只要看到一reg开头的单词,基本上都是跟正则有关
    	#SQL语句中使用正则,要使用关键字regexp声明
    
    mysql> select * from emp where name regexp '^a.*(a|z)$';
    +----+------+------+--------+--------------+--------+--------+-----------+
    | id | name | sex  | age | hire_date  | post    | post_comment | salary | office | depart_id |
    +----+------+-----+---------+--------------+--------+--------+-----------+
    |  1 | aa   | male |  77 | 2012-01-01 | teacher | NULL         |  10.10 |    401 |         1 |
    +----+------+------+--------+--------------+--------+--------+-----------+
    

    多表查询

    #创建多个表
    mysql> create table dep(
        id int,
        name varchar(20)
    );
    mysql> create table emp(
        id int primary key auto_increment,
        name varchar(20),
        sex enum('male','female') not null default 'male',
        age int,
        dep_id int
    );
    #插入数据
    mysql> insert dep values
    (200,'技术'),
    (201,'人力资源'),
    (202,'销售'),
    (203,'运营');
    mysql> insert emp(name,sex,age,dep_id) values
    ('jason','male',18,200),
    ('egon','female',48,201),
    ('kevin','male',38,201),
    ('nick','female',28,202),
    ('jerry','female',18,204);
    
    #表查询分为两类
    	1.联表查询
    	2.子查询
    
    #手动联表查询
        #笛卡尔积效果
    mysql> select * from emp,dep;
    +----+-------+--------+------+--------+------+--------------+
    | id | name  | sex    | age  | dep_id | id   | name         |
    +----+-------+--------+------+--------+------+--------------+
    |  1 | jason | male   |   18 |    200 |  200 | 技术         |
    |  1 | jason | male   |   18 |    200 |  201 | 人力资源     |
    |  1 | jason | male   |   18 |    200 |  202 | 销售         |
    |  1 | jason | male   |   18 |    200 |  203 | 运营         |
    |  2 | egon  | female |   48 |    201 |  200 | 技术         |
    |  2 | egon  | female |   48 |    201 |  201 | 人力资源     |
    |  2 | egon  | female |   48 |    201 |  202 | 销售         |
    |  2 | egon  | female |   48 |    201 |  203 | 运营         |
    |  3 | kevin | male   |   38 |    201 |  200 | 技术         |
    |  3 | kevin | male   |   38 |    201 |  201 | 人力资源     |
    |  3 | kevin | male   |   38 |    201 |  202 | 销售         |
    |  3 | kevin | male   |   38 |    201 |  203 | 运营         |
    |  4 | nick  | female |   28 |    202 |  200 | 技术         |
    |  4 | nick  | female |   28 |    202 |  201 | 人力资源     |
    |  4 | nick  | female |   28 |    202 |  202 | 销售         |
    |  4 | nick  | female |   28 |    202 |  203 | 运营         |
    |  5 | jerry | female |   18 |    204 |  200 | 技术         |
    |  5 | jerry | female |   18 |    204 |  201 | 人力资源     |
    |  5 | jerry | female |   18 |    204 |  202 | 销售         |
    |  5 | jerry | female |   18 |    204 |  203 | 运营         |
    +----+-------+--------+------+--------+------+--------------+
    	#联表查询中,无论是select后面的字段,还是where后面的字段,都要使用'表名.字段名'的格式
    mysql> select * from emp,dep where emp.dep_id=dep.id;
    +----+-------+--------+------+--------+------+--------------+
    | id | name  | sex    | age  | dep_id | id   | name         |
    +----+-------+--------+------+--------+------+--------------+
    |  1 | jason | male   |   18 |    200 |  200 | 技术         |
    |  2 | egon  | female |   48 |    201 |  201 | 人力资源     |
    |  3 | kevin | male   |   38 |    201 |  201 | 人力资源     |
    |  4 | nick  | female |   28 |    202 |  202 | 销售         |
    +----+-------+--------+------+--------+------+--------------+
    
    	#查询部门名为技术的员工信息
    mysql> select * from emp,dep where emp.dep_id=dep.id and dep.name='技术';
    +----+-------+------+------+--------+------+--------+
    | id | name  | sex  | age  | dep_id | id   | name   |
    +----+-------+------+------+--------+------+--------+
    |  1 | jason | male |   18 |    200 |  200 | 技术   |
    +----+-------+------+------+--------+------+--------+
    

    联表查询

    #专门联表的方法
    	#1.内连接(inner join),只取两张表有对应关系的记录(没有对应关系的两表数据直接剔除)
    mysql> select * from emp inner join dep on emp.dep_id=dep.id;
    +----+-------+--------+------+--------+------+--------------+
    | id | name  | sex    | age  | dep_id | id   | name         |
    +----+-------+--------+------+--------+------+--------------+
    |  1 | jason | male   |   18 |    200 |  200 | 技术         |
    |  2 | egon  | female |   48 |    201 |  201 | 人力资源     |
    |  3 | kevin | male   |   38 |    201 |  201 | 人力资源     |
    |  4 | nick  | female |   28 |    202 |  202 | 销售         |
    +----+-------+--------+------+--------+------+--------------+
    mysql> select * from emp inner join dep on emp.dep_id=dep.id where dep.name='技术';
    +----+-------+------+------+--------+------+--------+
    | id | name  | sex  | age  | dep_id | id   | name   |
    +----+-------+------+------+--------+------+--------+
    |  1 | jason | male |   18 |    200 |  200 | 技术   |
    +----+-------+------+------+--------+------+--------+
        #2.左连接(left join),在内连接的基础上,保留左表没有对应关系的数据
    mysql> select * from emp left join dep on emp.dep_id=dep.id;
    +----+-------+--------+------+--------+------+--------------+
    | id | name  | sex    | age  | dep_id | id   | name         |
    +----+-------+--------+------+--------+------+--------------+
    |  1 | jason | male   |   18 |    200 |  200 | 技术         |
    |  2 | egon  | female |   48 |    201 |  201 | 人力资源     |
    |  3 | kevin | male   |   38 |    201 |  201 | 人力资源     |
    |  4 | nick  | female |   28 |    202 |  202 | 销售         |
    |  5 | jerry | female |   18 |    204 | NULL | NULL         |	#
    +----+-------+--------+------+--------+------+--------------+
        #3.右连接(right join),在内连接的基础上,保留右表没有对应关系的数据
    mysql> select * from emp right join dep on emp.dep_id=dep.id;
    +------+-------+--------+------+--------+------+--------------+
    | id   | name  | sex    | age  | dep_id | id   | name         |
    +------+-------+--------+------+--------+------+--------------+
    |    1 | jason | male   |   18 |    200 |  200 | 技术         |
    |    2 | egon  | female |   48 |    201 |  201 | 人力资源     |
    |    3 | kevin | male   |   38 |    201 |  201 | 人力资源     |
    |    4 | nick  | female |   28 |    202 |  202 | 销售         |
    | NULL | NULL  | NULL   | NULL |   NULL |  203 | 运营         |	#
    +------+-------+--------+------+--------+------+--------------+
        #4.全连接(union),在内连接的基础上,保留左、右表没有对应关系的数据
    mysql> 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;
    +------+-------+--------+------+--------+------+--------------+
    | id   | name  | sex    | age  | dep_id | id   | name         |
    +------+-------+--------+------+--------+------+--------------+
    |    1 | jason | male   |   18 |    200 |  200 | 技术         |
    |    2 | egon  | female |   48 |    201 |  201 | 人力资源     |
    |    3 | kevin | male   |   38 |    201 |  201 | 人力资源     |
    |    4 | nick  | female |   28 |    202 |  202 | 销售         |
    |    5 | jerry | female |   18 |    204 | NULL | NULL         |
    | NULL | NULL  | NULL   | NULL |   NULL |  203 | 运营         |
    +------+-------+--------+------+--------+------+--------------+
    
    #这四种联表的方法以及现象,是对两表原始数据的合并,本质就是两表合为一表,后面可以对这个虚拟表直接操作
    

    子查询

    #子查询
    	将一张表的查询结果,作为另一张表的查询条件,这样的SQL语句称为子查询
        
    #as
    	1.可以给表起别名
        2.可以给虚拟表起别名
        3.可以给字段起别名
        
    #例1,员工Jason所在的部门?子查询如下
    mysql> select * from emp;
    +----+-------+--------+------+--------+
    | id | name  | sex    | age  | dep_id |
    +----+-------+--------+------+--------+
    |  1 | jason | male   |   18 |    200 |		#200
    |  2 | egon  | female |   48 |    201 |
    |  3 | kevin | male   |   38 |    201 |
    |  4 | nick  | female |   28 |    202 |
    |  5 | jerry | female |   18 |    204 |
    +----+-------+--------+------+--------+
    mysql> select * from dep;
    +------+--------------+
    | id   | name         |
    +------+--------------+
    |  200 | 技术         |	#可以看到Jason所在部门为'技术部'
    |  201 | 人力资源     |
    |  202 | 销售         |
    |  203 | 运营         |
    +------+--------------+
        #子查询完整语句
    mysql> select name from dep where id=(select dep_id from emp where name='jason');
    +--------+
    | name   |
    +--------+
    | 技术   |
    +--------+  
        
    #例2,查询每个部门最新入职的员工(先查询每个部门最先入职的员工,再按部门对应上连表查询)
    select t1.id,t1.name,t1.hire_data,t1.post,t2.* from emp as t1 
    inner join 
    (select post,max(hire_date) as max_date from emp group by post) as t2 
    on 
    t1.post=t2.post 
    where t1.hire_date=t2.max_date;
        
    #规律
    	表查询的结果,可以作为其他表的查询条件,也可以通过起别名的方式把他作为一个虚拟表,去跟其他的表做关联查询
        
    #例3,查询平均年龄在25岁以上的部门名
    	#联表
    mysql> select dep.name,avg(age) 
    from emp 
    inner join dep 
    on 
    emp.dep_id=dep.id 
    group by dep.name 
    having avg(age)>25;
    +--------------+----------+
    | name         | avg(age) |
    +--------------+----------+
    | 人力资源     |  43.0000 |
    | 销售         |  28.0000 |
    +--------------+----------+
    	#子查询
    mysql> select name from dep where id in
    (select dep_id from emp group by dep_id having avg(age)>25);
    +--------------+
    | name         |
    +--------------+
    | 人力资源     |
    | 销售         |
    +--------------+
    

    exists(了解)

    #关键字exists表示存在
    	在使用关键字exists时,内层查询语句不返回查询的数据,而是返回一个真假值True/False
        当返回True时,外层查询语句将进行查询
        当返回False时,外层查询语句不进行查询
        外层查询和内存查询,除了exists之外,并没有直接的代码联系
        
    #例
    	#子查询为True,则查询
    mysql> select dep_id from emp where exists(select id from dep where id>201);
    +--------+
    | dep_id |
    +--------+
    |    200 |
    |    201 |
    |    201 |
    |    202 |
    |    200 |
    +--------+
    	#子查询为False,则不查询
    mysql> select dep_id from emp where exists(select id from dep where id>2011);
    Empty set (0.00 sec)
    

    参考网站

    #数据库软件之所以可以操作数据库,原理是因为该软件把UI操作转化对应的SQL语句,发送到mysql服务端执行,再返回结果到该软件
    
    #ORM,对象关系映射
    	把一个复杂的功能映射成一个简单的接口,在UI界面展示
        能够让一个不会SQL语句的程序员,简单快速的操作mysql
        类			>>>			表
        对象			>>>			表中的一条数据
        对象获取属性	   >>>		  表中的某个字段对应的一条数据
    
    #navicat这款软件是很强大的
    	它可以连接多个版本的数据库,这一点打开navicat点击左上角的'连接'就可以看到了
    	连接本地的mysql之后,默认的连接名为'localhost_3306'
        双击'localhost_3306',相当于	 show databases;
        双击'库',相当于				use database_name;
        双击'表',相当于				show tables;
        双击'table_name',相当于		select * from table_name;
        单击'表',鼠标右键选择'设计表',相当于,desc table_name;				
        单击'localhost_3306',鼠标右键选择'新建数据库',指定库名、字符集(utf8mb4支持存储表情)
        双击新建的库,选择'表',鼠标右键选择'新建表',指定表名、类型、约束条件...等(设置键即主键:空格键、左键,设置或取消,记得主键一定要设置自增)
        
    #保存
    	表结构的修改需要手动保存,表数据的修改、外键的创建自动保存(界面左下角如果有√,修改数据之后记得点一下)
        
    #逆向数据库到模型
    	可以更好的展示表之间的关系
        单击库,右键选择'逆向数据库到模型'
        
    #模型
    	可以更方便的处理表之间的关系
        
    #转储
    	可以在不同的mysql数据库之间快速的传递'库数据'
    	单击库,右键选择'转储SQL文件'(记得刷新'表')
        
    #SQL
    	在navicat也可以写SQL语句
        选择库,点击查询,编辑SQL语句,点击运行即可
    

    练习题

    #1.查询所有的课程的名称,以及对应的任课老师姓名
    SELECT
    	course.cname,
    	teacher.tname 
    FROM
    	course
    	INNER JOIN teacher ON course.teacher_id = teacher.tid;
    #2.查询平均成绩大于80分的同学的姓名和平均成绩
    	#先联表,再分组
    SELECT
    	student.sname,
    	AVG( score.num ) 
    FROM
    	student
    	INNER JOIN score ON student.sid = score.sid 
    GROUP BY
    	student.sname 
    HAVING
    	AVG( score.num )> 80;
        
        #先分组,再联表
    SELECT
    	student.sname,
    	t1.f1 
    FROM
    	student
    	INNER JOIN ( SELECT student_id, AVG( num ) AS f1 FROM score GROUP BY student_id HAVING AVG( num )> 80 ) AS t1 ON student.sid = t1.student_id;
    #3.查询没有报李平老师课的学生姓名
    	#报李平老师课的学生(子查询)
    SELECT
    	sname AS '李平老师的学生' 
    FROM
    	student 
    WHERE
    	sid IN (
    	SELECT
    		student_id 
    	FROM
    		score 
    	WHERE
    		course_id IN (
    		SELECT
    			cid 
    		FROM
    			course 
    	WHERE
    	teacher_id = ( SELECT tid FROM teacher WHERE tname = '李平老师' )));
        #没有报李平老师课的学生(子查询)
    SELECT
    	sname AS '不是李平老师的学生' 
    FROM
    	student 
    WHERE
    	sid NOT IN (
    	SELECT
    		student_id 
    	FROM
    		score 
    	WHERE
    		course_id IN (
    		SELECT
    			cid 
    		FROM
    			course 
    	WHERE
    	teacher_id = ( SELECT tid FROM teacher WHERE tname = '李平老师' )));
    	#报李平老师课的学生(联表查询)
    SELECT
    	student.sname 
    FROM
    	student
    	INNER JOIN (
    	SELECT DISTINCT
    		student_id 
    	FROM
    		score
    	INNER JOIN ( SELECT course.cid FROM course INNER JOIN teacher ON teacher.tid = course.teacher_id WHERE teacher.tname = '李平老师' ) AS t1 ON score.course_id = t1.cid 
    	) AS t2 ON student.sid = t2.student_id;
        
    	#没有报李平老师课的学生(联表查询)
    SELECT
    	sname AS '不是李平老师的学生' 
    FROM
    	student 
    WHERE
    	sname NOT IN (
    	SELECT
    		student.sname 
    	FROM
    		student
    		INNER JOIN (
    		SELECT DISTINCT
    			student_id 
    		FROM
    			score
    			INNER JOIN ( SELECT course.cid FROM course INNER JOIN teacher ON teacher.tid = course.teacher_id WHERE teacher.tname = '李平老师' ) AS t1 ON score.course_id = t1.cid 
    		) AS t2 ON student.sid = t2.student_id 
    	);
    #4.查询没有同时选修物理课程和体育课程的学生姓名
    	#查询至少选修物理课程和体育一门课程的学生姓名
    SELECT
    	sname 
    FROM
    	student 
    WHERE
    	sid IN (
    	SELECT
    		score.student_id 
    	FROM
    		course
    		INNER JOIN score ON course.cid = score.course_id 
    WHERE
    	course.cname IN ( '物理', '体育' ));
    	#查询没有只选修物理课程和体育一门课程的学生姓名(通过count,区分种类)
    SELECT
    	sname 
    FROM
    	student 
    WHERE
    	sid IN (
    	SELECT
    		student_id 
    	FROM
    		score 
    	WHERE
    		course_id IN (
    		SELECT
    			cid 
    		FROM
    			course 
    		WHERE
    		cname IN ( '物理', '体育' )) 
    	GROUP BY
    		student_id 
    	HAVING
    	COUNT( course_id )= 1 
    	);
    #5.查询挂科超过两门(包括两门)的学生姓名和班级
    SELECT
    	t1.sname,
    	class.caption 
    FROM
    	class
    	INNER JOIN (
    	SELECT
    		* 
    	FROM
    		student 
    WHERE
    	sid = ( SELECT student_id FROM score WHERE num < 60 GROUP BY student_id HAVING count( num ) > 1 )) AS t1 ON class.cid = t1.class_id;
    
    #总结
    	select ...as... 
        from table_name ...
        inner join ... on ...=... 
        where ...=... 
        group by ... 
        having ...;
        #where后面的等号后面只能跟一个确定的值,on后面的等号的后面可以跟多个值
        #使用as给虚拟表起别名,在多表联查中的作用很重要,可以让多张表中的数据在一张表中展示指定的字段(as前面的虚拟表必须加括号)
        #要使用虚拟表中的聚合函数字段,必须使用as给虚拟表中的聚合函数字段起别名
    

    python操作mysql

    #python操作mysql需要使用pymysql模块
    
    import pymysql
    conn = pymysql.connect(
        host = '127.0.0.1',
        port = 3306,
        user = 'root',
        password = '1',
        database = 'test3',
        charset = 'utf8'    #不要加-
    )
    #生成一个游标对象,以字典的形式返回表数据,即{'字段':'数据'}
    cursor = conn.cursor(pymysql.cursors.DictCursor)
    sql = 'select * from test3.t3'
    #执行传入的SQL语句,有返回值,返回值为执行SQL语句得到的数据的条数
    cursor.execute(sql)
    #迭代器,返回值为一条表数据
    print(cursor.fetchone())
    print(cursor.fetchone())
    # cursor.scroll(1,'absolute')     #移动光标,相对于起始位置向后移动几位
    # cursor.scroll(-1,'relative')       #移动光标,相对于当前位置向后移动几位
    #一次性的获取所有的表数据,在列表中
    print(cursor.fetchall())
    
    {'id': 1, 'age': 18}
    {'id': 2, 'age': 19}
    [{'id': 3, 'age': 20}]
    

    SQL注入问题

    #SQL注入问题
    	SQL注入问题就是利用注释等具有特殊意义的符号,来完成一些骚操作
        禁止用户输入含有特殊符号的用户名和密码,可以有效的防止SQL注入问题
    
    import pymysql
    conn = pymysql.connect(
        host = '127.0.0.1',
        port = 3306,
        user = 'root',
        password = '1',
        database = 'test3',
        charset = 'utf8'    #不要加-
    )
    cursor = conn.cursor(pymysql.cursors.DictCursor)
    while type:
        username = input('请输入用户名>>>: ').strip()
        password = input('请输入用户密码>>>: ').strip()
        sql = "select * from user where name='%s' and password='%s'"%(username,password)
        res = cursor.execute(sql)
        if res:
            print(cursor.fetchall())
        else:
            print('用户名或密码输入错误')
            
    请输入用户名>>>: jason' -- s
    请输入用户密码>>>: 
    [{'id': 1, 'name': 'jason', 'password': '123'}]        
    
    请输入用户名>>>: s' or 1=1 -- s
    请输入用户密码>>>:
    [{'id': 1, 'name': 'jason', 'password': '123'}, {'id': 2, 'name': 'egon', 'password': '123'}, {'id': 3, 'name': 'tank', 'password': '123'}, {'id': 4, 'name': 'kevin', 'password': '123'}]
    
    #SQL注入问题的解决方法
    	使用python代码来操作mysql,为了避免SQL注入的问题,关键的数据(用户名、密码等),不能手动拼接SQL语句,要使用excute()来拼接
        excute(sql,(arg1,arg2)),会自动识别sql语句中的%s,自动替换
        
    import pymysql
    conn = pymysql.connect(
        host = '127.0.0.1',
        port = 3306,
        user = 'root',
        password = '1',
        database = 'test3',
        charset = 'utf8'    #不要加-
    )
    cursor = conn.cursor(pymysql.cursors.DictCursor)
    while type:
        username = input('请输入用户名>>>: ').strip()
        password = input('请输入用户密码>>>: ').strip()
        sql = "select * from user where name=%s and password=%s"	#注意格式
        res = cursor.execute(sql,(username,password))
        if res:
            print(cursor.fetchall())
        else:
            print('用户名或密码输入错误')
    

    python操作mysql之增删改

    #python操作mysql之增删改的操作,必须在代码的结尾加上commit()
    
    #手动commit
    import pymysql
    conn = pymysql.connect(
        host = '127.0.0.1',
        port = 3306,
        user = 'root',
        password = '1',
        database = 'test3',
        charset = 'utf8'    #不要加-
    )
    cursor = conn.cursor(pymysql.cursors.DictCursor)
    # sql = "insert user(name,password) values('jerry','123')"
    # sql = 'update user set name="jasonhh" where id="1"'
    sql = "delete from user where id='6142'"
    cursor.execute(sql)
    conn.commit()
    
    #设置自动commit
    	#配置自动commit之后,python操作mysql之增删改的操作都不需要再手动commit
    import pymysql
    conn = pymysql.connect(
        host = '127.0.0.1',
        port = 3306,
        user = 'root',
        password = '1',
        database = 'test3',
        charset = 'utf8',    #不要加-
        autocommit = True
    )
    cursor = conn.cursor(pymysql.cursors.DictCursor)
    # sql = "insert user(name,password) values('jerry','123')"
    # sql = 'update user set name="jasonhh" where id="1"'
    sql = "delete from user where id='6142'"
    cursor.execute(sql)
    

    视图

    #1.什么是视图
    	视图就是通过查询的得到一张虚拟表,然后保存下来,下次直接使用即可,这个表就叫做视图
        #视图对应的文件只有一个table_name.frm,里面记录这视图的表结构,视图的数据还是来源于原来的表
        #不要改动视图中的数据,因为可能会影响到其他的表(#不能改)
       
    #2.为什么要使用视图
    	如果需要重复的使用一张虚拟表,使用了视图的话可以不用频繁的查询
        
    #3.怎么使用视图
    create VIEW teacher_course as SELECT * FROM teacher INNER JOIN course on teacher.tid=course.teacher_id;
    show tables;
    select * from teacher_course;
    
    #工作中一般不使用视图来写业务逻辑的原因
    	1.无法对视图进行'增删改',容易造成业务逻辑混乱
        2.视图文件占用磁盘空间
    

    触发器

    #触发器
    	当你对指定表的数据进行'增删改'的时候,条件满足则自动触发触发器的运行
    
    #mysql默认提示符
    	可以使用关键字delimiter,修改mysql默认提示符
        delimiter $$
        使用关键字delimiter修改mysql默认提示符的行为,只对'当前窗口有效'
    
    #根据触发器与SQL语句的作用先后,触发器分为6种
    	1.增前
        2.增后
        3.删前
        4.删后
        5.改前
        6.改后
        
    #触发器语法结构
    delimiter $$
    create trigger tri_before/after_insert/delete/update_table_name 
    after/before 
    insert/delete/update on 
    table_name 
    for each row 
    begin
    	sql语句;
    end$$
    delimiter ;
    
    #例
    	#再向cmd表插入数据之后,如果success字段为no,则向errorlog表插入记录
        
        #创建表cmd
    CREATE TABLE cmd (
    	id INT PRIMARY KEY auto_increment,
    	USER CHAR ( 32 ),
    	priv CHAR ( 10 ),
    	cmd CHAR ( 64 ),
    	sub_time datetime,		#cmd提交时间
    	success enum ( 'yes', 'no' ));		#0表示cmd执行失败
    
    	#创建表errlog
    CREATE TABLE errlog ( 
        id INT PRIMARY KEY auto_increment, 
        err_cmd CHAR ( 64 ), 
        err_time datetime );
    
    	#创建触发器(条件触发器)
    delimiter $$
    CREATE TRIGGER tri_after_insert_cmd AFTER INSERT ON cmd FOR EACH ROW
    BEGIN
    	IF
    		NEW.success = 'no' THEN
    			INSERT errlog ( err_cmd, err_time )
    		VALUES
    			( NEW.cmd, NEW.sub_time );
    	END IF;
    END $$
    delimiter ;
    
    	#向cmd表插入数据
    INSERT cmd ( USER, priv, cmd, sub_time, success )
    VALUES
    	( 'syy', '0751', 'ls -l /etc', NOW(), 'yes' ),
    	( 'syy', '0751', 'cat /etc/password', NOW(), 'no' ),
    	( 'ee', '0755', 'useradd xxx', NOW(), 'no' ),
    	( 'ee', '0755', 'ps aux', NOW(), 'yes' );
        
    	#查看errlog表中的记录
    SELECT * from errlog;
    1	cat /etc/password	2020-12-28 09:47:02
    2	useradd xxx			2020-12-28 09:47:02
    
        #删除触发器
    drop TRIGGER tri_after_insert_cmd;
    
    #mysql中,查看触发器的两种方法
    	1.show TRIGGERS;
        2.select * from information_schema.`TRIGGERS`;
    

    事务

    #事务
    	事务包含多条SQL语句,这些SQL语句要么同时成功,要么全部失败(只要有一台SQL语句失败 )
    
    #事务的四大特性:ACID
    	A:原子性
        	一个事务是一个不可分割的工作单位,事务中包含的多个操作,要么都做,要么都不做
        C:一致性
        	事务必须是使数据库从一个一致状态编导另一个一致状态,一致性与原子性是密切相关的
        I:隔离性
        	一个事务的执行不能被其他事务干扰,即一个事务内部的操作及使用的数据对并发的其他事务是隔离的,并发执行的各个事务之间不能相互干扰
        D:持久性
        	持久性也称永久性,指一个事务一旦提交它对数据库中的数据就应该是永久性的,接下来的其他操作或故障不应该对其有任何影响
        
    #开启事务
    	start transaction
        
    #事务回滚
    	rollback
        
    #永久性更改
    	commit
        #开启事务之后,只要没有执行commit操作,数据就没有真正刷新到硬盘
        #commit的时候,会检测事务操作是否完整,不完整的话会回到上一个状态,如果完整就执行commit操作,刷新数据到硬盘,更新内存中的数据
        
    #例
    CREATE TABLE USER (
        id INT PRIMARY KEY auto_increment, 
        NAME CHAR ( 32 ), 
        balance INT 
    );
    INSERT USER(NAME, balance) VALUES 
    ( 'syy', 1000 ),
    ( 'egon', 1000 ),
    ( 'jason', 1000 );
    
    	#修改数据之前先开启事务操作
    start transaction;
    
    	#修改数据
    update user set balance=900 where name='syy';		#买东西支付100元
    update user set balance=1010 where name='egon';		#中介拿走10元
    update user set balance=1090 where name='jason';		#卖家拿走90元
    
    	#查看数据
    select * from user;
    1	syy		900
    2	egon	1010
    3	jason	1090
    
    	#回滚操作(没有commit,也没有rollback的话,自动commit)
    rollback;
    
    	#验证数据
    select * from user;
    1	syy		900
    2	egon	1010
    3	jason	1090
    
    #python代码解释事务
    try:
        update user set balance=900 where name='syy';	
    	update user set balance=1010 where name='egon';	
    	update user set balance=1090 where name='jason';
    except 异常:
        rollback;
    else:
        commit;
    

    存储过程

    #存储过程
    	存储过程就类似于python中的自定义函数,内部封装了操作数据库的SQL语句,后续想要实现相应的操作,主需要调用存储过程即可
        #存储过程在哪个库下面创建,就只能在对应的库下面才能使用(可以在别的库下使用:call test.p_name(m,n,@args);)
    	
    #1.创建'无参''存储过程'
    delimiter $$
    create proceduer p_name()
    begin
    	select * from user;
    end $$
    delimiter ;
    
    #调用存储过程
    call p1();
    
    #2.创建'有参''存储过程'
    delimiter $$
    create proceduer p_name(
    	in m int,			#不能被返回
        in n int,
        out res int			#可以被返回
        #inout xxx int		#既可以进,又可以出
    ) 
    begin
    	select * from user;
    end $$
    delimiter ;
    
    #例
    	#res类似于标志位,用来标识存储器是否执行成功
    delimiter $$
    create proceduer p1(
    	in m int,
        in n int,
        out res int
    )
    begin
    	select tname from teacher where tid > m and tid < n;
        set res=0;
    end $$
    delimiter ;
    set @res=10;			#设置变量	
    SELECT @res;			#查看变量
    CALL p1(1,5,@res);		#调用有参'存储过程'
    SELECT @res;			#再次查看变量 
    
    #使用pymysql使用存储过程
    import pymysql
    conn = pymysql.connect(
        host = '127.0.0.1',
        port = 3306,
        user = 'root',
        password = '1',
        database = 'test',
        charset = 'utf8',    #不要加-
        autocommit = True
    )
    cursor = conn.cursor(pymysql.cursors.DictCursor)
    #调用存储过程,相当于navicate中的:call p1(1,5,@res)
    cursor.callproc('p1',(1,5,10))      #内部自动用变量名存储了对应的值(@_存储过程名_索引值:@_p1_0=1,@_p1_1=5,@_p1_2=10)
    print(cursor.fetchall())
    cursor.execute('selete @_p1_0')
    print(cursor.fetchall())
    cursor.execute('selete @_p1_1')
    print(cursor.fetchall())
    cursor.execute('selete @_p1_2')
    print(cursor.fetchall())
    

    内置函数

    参考网站

    #
    
    #例
    create table blog(id int primary key auto_increment,name char(32),sub_time datetime);
    insert blog(name,sub_time) values
    ('第一篇','2020-11-11 11:11:11'),
    ('第二篇','2020-11-11 11:11:12'),
    ('第三篇','2020-11-11 11:11:13');
    select date_format(sub_time,'%Y-%m'),count(id) from blog group by date_format(sub_time,'%Y-%m');
    date_format(sub_time,'%Y-%m') | count(id)   |
    2020-11							2			|
    

    流程控制

    #if条件语句
    delimiter //
    create procedure proc_if()
    begin
    	declare i int default 0;
        if i=1 then
        	select 1;
        elseif i=2 then
        	select 2;
        else
        	select 7;
    end //
    delimiter ;
    
    #while循环
    delimiter //
    create procedure proc_while()
    begin
    	declare num int;
        set num=0;
        while num < 10 DO
        	select num;
            set num = num + 1;
        end while;
    end //
    delimiter ;
    

    索引

    #索引
    	数据是存在于硬盘上的,拿查询数据不可避免的需要进行IO操作
    	索引在mysql中也叫做键,是存储引擎用于快速找到记录的一种数据结构
        #索引的本质:通过不断的缩小数据的范围,来筛选出想要的结果,同时把随机的事件变成顺序的事件,总而言之,通过索引机制,我们总是可以用同一种查找方式来锁定数据
        innodb存储引擎中,表索引和表数据在同一个文件中
        在表中有大数据的前提下,创建索引的速度会很慢,索引创建完毕后,对表的查询性能会大幅度提升,但是写的性能会降低
        
    #索引的种类
    	1.主键索引		primary key
        2.唯一键索引		unique key
        3.普通索引		index key
        #注意,外键(foreign key)不是用来加速查询用的
        #上面三种key,前两种除了有加速查询的效果之外,还有额外的约束条件(主键索引:非空且唯一,唯一键索引:唯一),而index key没有任何约束功能,只会加速查询
    
  • 相关阅读:
    修改spring MVC配置文件的默认位置
    TCP三次握手四次挥手视频讲解
    Redis端口配置
    applicationContext-redis.xml
    PageHelper的分页原理
    maven的三种工程 pom工程、jar工程、war工程的区别和使用
    springboot 整合spring Data JPA的资源配置pom.xml
    Spring知识点整理
    jdk1.6 和 jdk1.7 区别
    linux中安装redis
  • 原文地址:https://www.cnblogs.com/syy1757528181/p/14215069.html
Copyright © 2020-2023  润新知