5.15 mysql 数据库(数据库/表操作/索引/pymysql/备份与恢复/事务/锁) 学习笔记
文章目录
- 1 初始数据库
- 1)数据库
- 2)mysql
- 3)和用户权限相关的
- 4)基本操作
- 2 表操作
- 1)存储引擎
- 2)表和数据的一些基本操作
- 3)mysql中的数据类型
- 4)表的完整性约束
- 5)修改表结构
- 6)多表结构的创建和分析
- 3 数据操作
- 1)插入数据
- 2)修改数据
- 3)删除数据
- 4)查询数据
- 4 mysql 索引
- 1)索引原理
- 2)索引的数据结构——树
- 5 pymysql
- 1)python操作mysql数据库
- 2)sql注入
- 6 mysql的库/表备份与恢复
- 1)备份
- 2)恢复
- 7 事务/锁
1 初始数据库
1)数据库
- 数据库(DataBase,简称DB)
- 数据库即存放数据的仓库,只不过这个仓库是在计算机存储设备上,而且数据是按一定的格式存放的
- 数据库是长期存放在计算机内、有组织、可共享的数据集合。
- 数据库中的数据按一定的数据模型组织、描述和储存,具有较小的冗余度、较高的数据独立性和易扩展性,并可为各种 用户共享
- 数据库管理系统(DataBase Management System 简称DBMS)
- 用于科学地组织和存储数据,如高效获取和维护数据的系统软件
- 如MySQL、Oracle、SQLite、Access、MS SQL Server
- mysql主要用于大型门户
- oracle主要用于银行、铁路、飞机场等。该数据库功能强大,软件费用高。
- 数据库服务器、数据管理系统、数据库、表与记录的关系
- 记录:1 小明 123456789 22(多个字段的信息组成一条记录,即文件中的一行内容)
- 表:userinfo, studentinfo, courseinfo(即文件)
- 数据库:db(即文件夹)
- 数据库管理系统:如mysql(是一个软件)
- 数据库服务器:一台计算机(对内存要求比较高)
- 总结:
- 数据库服务器:运行数据库管理软件
- 数据库管理软件:管理-数据库
- 数据库:即文件夹,用来组织文件/表
- 表:即文件,用来存放多行内容/多条记录
2)mysql
- 数据库管理软件分类
- 关系型:
- 关系型数据库需要有表结构
- 如sqllite,db2,oracle,access,sql server,MySQL,注意:sql语句通用
- 非关系型:
- 非关系型数据库是key-value存储的,没有表结构
- mongodb,redis,memcache (既可以做消息中间件,也可以做数据库)
- 关系型:
- mysql
- MySQL 是最流行的关系型数据库管理系统之一,在 WEB 应用方面,MySQL是最好的 RDBMS (Relational Database Management System,关系数据库管理系统) 应用软件。
- MySQL是一种关系数据库管理系统,关系数据库将数据保存在不同的表中,而不是将所有数据放在一个大仓库内,这样就增加了速度并提高了灵活性。
- MySQL所使用的 SQL 语言是用于访问数据库的最常用标准化语言。
- 特点:体积小、速度快、成本低,开放源码
3)和用户权限相关的
- 环境变量
- 在命令行模式下输入python–>实际执行
python.exe
- 在任何目录下等能找到
python.exe
文件 - 只有在环境变量中输入
python.exe
文件的路径才能在任意位置输入python命令启动python解释器
- 在命令行模式下输入python–>实际执行
- 安装mysql服务——
mysqld install mysql
服务就被注册到操作系统中 - 启动mysql服务——
net start mysql
- 停止mysql服务——
net stop mysql
- 启动mysql客户端连接到server端(登录)——
mysql -uroot -p
- 查看当前登录用户——
mysql>select user();
- 给当前用户设置密码——
mysql>set password = password('123');
- 创建一个其他用户——
create user 'guest'@'主机IP/主机域名' identified by '123';
- 远程登陆——
mysql -uroot -p123 -h 192.168.10.3
- 给一个用户授权
grant 权限类型 on ftp.* to 'guest'@'192.168.14.%';
grant all/select/insert/update/delete
mysql> flush privileges;
# 刷新使授权立即生效
4)基本操作
- 操作数据库
- 查看所有数据库——
show databases;
- 创建一个数据库——
creat database 数据库名;
- 切换到这个数据库下——
use 数据库名;
- 查看数据库下的所有表——
show tables;
- 删除数据库——
drop databse 数据库名;
- 查看所有数据库——
- 操作表
- 创建一张表——
create table student(name char(12),age int);
- 查看表结构——
desc student;
- 创建一张表——
- 操作数据
- 插入数据——
insert into student values ('wusir',73);
- 查询数据——
select * from student;
- 修改数据——
update student set age=85 where name='alex';
- 删除数据——
delete from student where name = 'alex';
- 插入数据——
2 表操作
1)存储引擎
定义:存储数据的方式
常用的三个存储引擎:
- Innodb存储引擎
- 数据和索引存储在一起 2个文件——数据索引\表结构
- 数据持久化
- 支持事务:
- 为了保证数据的完整性**,将多个操作变成原子性操作**
- 保持数据安全
- 支持行级锁 :
- 修改的行少的时候使用
- 修改数据频繁的操作
- 支持表级锁 :
- 批量修改多行的时候使用
- 对于大量数据的同时修改
- 支持外键 :
- 约束两张表中的关联字段不能随意的添加\删除
- 能够降低数据增删改的出错率
- Myisam存储引擎
- 数据和索引不存储在一起 3个文件——数据\索引\表结构
- 数据持久化
- 只支持表锁
- Memory存储引擎
- 数据存储在内存中, 1个文件——表结构
- 数据断电消失
- 三个存储引擎的文件存储结构
- engine1——Innodb engine2——Myisam engine3——Memory
- Innodb存储引擎
面试题
- 你了解mysql的存储引擎么?
- 答案如上
- 你的项目用了什么存储引擎,为什么?
- 用了innodb数据存储引擎
- 多个用户操作的过程中对同一张表的数据同时做修改
- innodb支持行级锁,所以我们使用了这个存储引擎
- 为了适应程序未来的扩展性,扩展新功能的时候可能会用到…(事务),涉及到要维护数据的完整性
- 项目中有一两张xx xx表,之间的外键关系是什么,一张表的修改或者删除比较频繁,怕出错所以做了外键约束
- 你了解mysql的存储引擎么?
存储引擎在mysql中的引用
- 存储引擎相关语句
- 查看当前的默认存储引擎
mysql> show variables like 'default_storage_engine';
- 查看当前数据库支持的存储引擎
mysql> show engines;
- 查看当前的默认存储引擎
- 存储引擎相关语句
指定存储引擎建表
- 指定存储引擎建表
mysql> create table engine1(id int(4),name char(20)) ENGINE=InnoDB;
mysql> create table engine2(id int(4),name char(20)) ENGINE=MyISAM;
mysql> create table engine3(id int(4),name char(20)) ENGINE=Memory;
- 也可以使用
alter table
语句,修改一个已经存在的表的存储引擎。mysql> alter table engine2(表名) engine = innodb;
- 指定存储引擎建表
2)表和数据的一些基本操作
创建表
语法
create table 表名( 字段名1 类型[(宽度) 约束条件], 字段名2 类型[(宽度) 约束条件], 字段名3 类型[(宽度) 约束条件] ); 放在[]内的内容可以不写
往表中写入数据的方式
insert into 表 values (值1,值2,值3);
- 这张表有多少的字段,就需要按照字段的顺序写入多少个值
insert into 表 values (值1,值2,值3),(值1,值2,值3),(值1,值2,值3);
- 一次性写入多条数据
insert into 表 (字段1,字段3 ) values (值1,值3);
- 指定字段名写入,可以任意的选择表中你需要写入的字段进行
查表中的数据
select * from 表;
查看表结构
desc 表名;
- 能够查看到有多少个字段\类型\长度,看不到表编码,引擎,具体的约束信息只能看到一部分
show create table 表名;
- 能查看字段\类型\长度\编码\引擎\约束
3)mysql中的数据类型
数字
类型 大小 范围(有符号) 范围(无符号)unsigned约束 用途 TINYINT 1 字节 (-128,127) (0,255) 小整数值 SMALLINT 2 字节 (-32 768,32 767) (0,65 535) 大整数值 MEDIUMINT 3 字节 (-8 388 608,8 388 607) (0,16 777 215) 大整数值 INT或INTEGER 4 字节 (-2 147 483 648,2 147 483 647) (0,4 294 967 295) 大整数值 BIGINT 8 字节 (-9 233 372 036 854 775 808,9 223 372 036 854 775 807) (0,18 446 744 073 709 551 615) 极大整数值 FLOAT 4 字节float(255,30) (-3.402 823 466 E+38,-1.175 494 351 E-38),0,(1.175 494 351 E-38,3.402 823 466 351 E+38) 0,(1.175 494 351 E-38,3.402 823 466 E+38) 单精度 浮点数值 DOUBLE 8 字节double(255,30) (-1.797 693 134 862 315 7 E+308,-2.225 073 858 507 201 4 E-308),0,(2.225 073 858 507 201 4 E-308,1.797 693 134 862 315 7 E+308) 0,(2.225 073 858 507 201 4 E-308,1.797 693 134 862 315 7 E+308) 双精度 浮点数值 DECIMAL 对DECIMAL(M,D) ,如果M>D,为M+2否则为D+2double(65,30) 依赖于M和D的值 依赖于M和D的值 小数值 实例
整数实例
# 创建表一个是默认宽度的int,一个是指定宽度的int(5) mysql> create table t1 (id1 int,id2 int(5)); Query OK, 0 rows affected (0.02 sec)# 像t1中插入数据1,1 mysql> insert into t1 values (1,1); Query OK, 1 row affected (0.01 sec)# 可以看出结果上并没有异常 mysql> select * from t1; +------+------+ | id1 | id2 | +------+------+ | 1 | 1 | +------+------+ row in set (0.00 sec)# 那么当我们插入了比宽度更大的值,会不会发生报错呢? mysql> insert into t1 values (111111,111111); Query OK, 1 row affected (0.00 sec)# 答案是否定的,id2仍然显示了正确的数值,没有受到宽度限制的影响 mysql> select * from t1; +------------+--------+ | id1 | id2 | +------------+--------+ | 0000000001 | 00001 | | 0000111111 | 111111 | +------------+--------+ rows in set (0.00 sec)# 修改id1字段 给字段添加一个unsigned表示无符号 mysql> alter table t1 modify id1 int unsigned; Query OK, 0 rows affected (0.01 sec) Records: 0 Duplicates: 0 Warnings: 0mysql> desc t1; +-------+------------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +-------+------------------+------+-----+---------+-------+ | id1 | int(10) unsigned | YES | | NULL | | | id2 | int(5) | YES | | NULL | | +-------+------------------+------+-----+---------+-------+ rows in set (0.01 sec)# 当给id1添加的数据大于214748364时,可以顺利插入 mysql> insert into t1 values (2147483648,2147483647); Query OK, 1 row affected (0.00 sec)# 当给id2添加的数据大于214748364时,会报错 mysql> insert into t1 values (2147483647,2147483648); ERROR 1264 (22003): Out of range value for column 'id2' at row 1int整数示例
小数实例
# 创建表的三个字段分别为float,double和decimal参数表示一共显示5位,小数部分占2位 mysql> create table t2 (id1 float(5,2),id2 double(5,2),id3 decimal(5,2)); Query OK, 0 rows affected (0.02 sec)# 向表中插入1.23,结果正常 mysql> insert into t2 values (1.23,1.23,1.23); Query OK, 1 row affected (0.00 sec)mysql> select * from t2; +------+------+------+ | id1 | id2 | id3 | +------+------+------+ | 1.23 | 1.23 | 1.23 | +------+------+------+ row in set (0.00 sec)# 向表中插入1.234,会发现4都被截断了 mysql> insert into t2 values (1.234,1.234,1.234); Query OK, 1 row affected, 1 warning (0.00 sec)mysql> select * from t2; +------+------+------+ | id1 | id2 | id3 | +------+------+------+ | 1.23 | 1.23 | 1.23 | | 1.23 | 1.23 | 1.23 | +------+------+------+ rows in set (0.00 sec)# 向表中插入1.235发现数据虽然被截断,但是遵循了四舍五入的规则 mysql> insert into t2 values (1.235,1.235,1.235); Query OK, 1 row affected, 1 warning (0.00 sec)mysql> select * from t2; +------+------+------+ | id1 | id2 | id3 | +------+------+------+ | 1.23 | 1.23 | 1.23 | | 1.23 | 1.23 | 1.23 | | 1.24 | 1.24 | 1.24 | +------+------+------+ rows in set (0.00 sec)# 建新表去掉参数约束 mysql> create table t3 (id1 float,id2 double,id3 decimal); Query OK, 0 rows affected (0.02 sec)# 分别插入1.234 mysql> insert into t3 values (1.234,1.234,1.234); Query OK, 1 row affected, 1 warning (0.00 sec)# 发现decimal默认值是(10,0)的整数 mysql> select * from t3; +-------+-------+------+ | id1 | id2 | id3 | +-------+-------+------+ | 1.234 | 1.234 | 1 | +-------+-------+------+ row in set (0.00 sec)# 当对小数位没有约束的时候,输入超长的小数,会发现float和double的区别 mysql> insert into t3 values (1.2355555555555555555,1.2355555555555555555,1.2355555555555555555555); Query OK, 1 row affected, 1 warning (0.00 sec)mysql> select * from t3; +---------+--------------------+------+ | id1 | id2 | id3 | +---------+--------------------+------+ | 1.234 | 1.234 | 1 | | 1.23556 | 1.2355555555555555 | 1 | +---------+--------------------+------+ rows in set (0.00 sec)
字符串
类型 大小 用途 CHAR 0-255字节 定长字符串 VARCHAR 0-65535 字节 变长字符串 TINYBLOB 0-255字节 不超过 255 个字符的二进制字符串 TINYTEXT 0-255字节 短文本字符串 BLOB 0-65 535字节 二进制形式的长文本数据 TEXT 0-65 535字节 长文本数据 MEDIUMBLOB 0-16 777 215字节 二进制形式的中等长度文本数据 MEDIUMTEXT 0-16 777 215字节 中等长度文本数据 LONGBLOB 0-4 294 967 295字节 二进制形式的极大文本数据 LONGTEXT 0-4 294 967 295字节 极大文本数据 实例
char/varchar实例
mysql> create table t9 (v varchar(4),c char(4)); Query OK, 0 rows affected (0.01 sec)mysql> insert into t9 values ('ab ','ab '); Query OK, 1 row affected (0.00 sec)# 在检索的时候char数据类型会去掉空格 mysql> select * from t9; +------+------+ | v | c | +------+------+ | ab | ab | +------+------+ row in set (0.00 sec)# 来看看对查询结果计算的长度 mysql> select length(v),length(c) from t9; +-----------+-----------+ | length(v) | length(c) | +-----------+-----------+ | 4 | 2 | +-----------+-----------+ row in set (0.00 sec)# 给结果拼上一个加号会更清楚 mysql> select concat(v,'+'),concat(c,'+') from t9; +---------------+---------------+ | concat(v,'+') | concat(c,'+') | +---------------+---------------+ | ab + | ab+ | +---------------+---------------+ row in set (0.00 sec)# 当存储的长度超出定义的长度,会截断 mysql> insert into t9 values ('abcd ','abcd '); Query OK, 1 row affected, 1 warning (0.01 sec)mysql> select * from t9; +------+------+ | v | c | +------+------+ | ab | ab | | abcd | abcd | +------+------+ rows in set (0.00 sec)char/varchar示例
时间日期
类型 大小 (字节) 范围 格式 用途 DATE 3 1000-01-01/9999-12-31 YYYY-MM-DD 年月日 TIME 3 ‘-838:59:59’/‘838:59:59’ HH:MM:SS 时分秒 YEAR 1 1901/2155 YYYY 年份值 DATETIME 8 1000-01-01 00:00:00/9999-12-31 23:59:59 YYYY-MM-DD HH:MM:SS 年月日时分秒 TIMESTAMP 4 1970-01-01 00:00:00/2038结束时间是第 2147483647 秒,北京时间 2038-1-19 11:14:07,格林尼治时间 2038年1月19日 凌晨 03:14:07 YYYYMMDD HHMMSS 混合日期和时间值,时间戳 date/time/datetime实例
mysql> create table t4 (d date,t time,dt datetime); Query OK, 0 rows affected (0.02 sec)mysql> desc t4; +-------+----------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +-------+----------+------+-----+---------+-------+ | d | date | YES | | NULL | | | t | time | YES | | NULL | | | dt | datetime | YES | | NULL | | +-------+----------+------+-----+---------+-------+ 3 rows in set (0.01 sec)mysql> insert into t4 values (now(),now(),now()); Query OK, 1 row affected, 1 warning (0.01 sec)mysql> select * from t4; +------------+----------+---------------------+ | d | t | dt | +------------+----------+---------------------+ | 2018-09-21 | 14:51:51 | 2018-09-21 14:51:51 | +------------+----------+---------------------+ 1 row in set (0.00 sec)mysql> insert into t4 values (null,null,null); Query OK, 1 row affected (0.01 sec)mysql> select * from t4; +------------+----------+---------------------+ | d | t | dt | +------------+----------+---------------------+ | 2018-09-21 | 14:51:51 | 2018-09-21 14:51:51 | | NULL | NULL | NULL | +------------+----------+---------------------+ 2 rows in set (0.00 sec)
timestamp实例
mysql> create table t5 (id1 timestamp); Query OK, 0 rows affected (0.02 sec)mysql> desc t5; +-------+-----------+------+-----+-------------------+-----------------------------+ | Field | Type | Null | Key | Default | Extra | +-------+-----------+------+-----+-------------------+-----------------------------+ | id1 | timestamp | NO | | CURRENT_TIMESTAMP | on update CURRENT_TIMESTAMP | +-------+-----------+------+-----+-------------------+-----------------------------+ 1 row in set (0.00 sec)# 插入数据null mysql> insert into t5 values (null); Query OK, 1 row affected (0.00 sec)mysql> select * from t5; +---------------------+ | id1 | +---------------------+ | NULL | +---------------------+ 1 row in set (0.00 sec)#添加一列 默认值是'0000-00-00 00:00:00' mysql> alter table t5 add id2 timestamp; Query OK, 0 rows affected (0.02 sec) Records: 0 Duplicates: 0 Warnings: 0mysql> show create table t5 \G; *************************** 1. row ***************************Table: t5 Create Table: CREATE TABLE `t5` (`id1` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,`id2` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00' ) ENGINE=InnoDB DEFAULT CHARSET=utf8 1 row in set (0.00 sec)ERROR: No query specified# 手动修改新的列默认值为当前时间 mysql> alter table t5 modify id2 timestamp default current_timestamp; Query OK, 0 rows affected (0.02 sec) Records: 0 Duplicates: 0 Warnings: 0mysql> show create table t5 \G; *************************** 1. row ***************************Table: t5 Create Table: CREATE TABLE `t5` (`id1` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,`id2` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ) ENGINE=InnoDB DEFAULT CHARSET=utf8 1 row in set (0.00 sec)ERROR: No query specifiedmysql> insert into t5 values (null,null); Query OK, 1 row affected (0.01 sec)mysql> select * from t5; +---------------------+---------------------+ | id1 | id2 | +---------------------+---------------------+ | 2018-09-21 14:56:50 | 0000-00-00 00:00:00 | | 2018-09-21 14:59:31 | 2018-09-21 14:59:31 | +---------------------+---------------------+ 2 rows in set (0.00 sec)mysql> create table t6 (t1 timestamp); Query OK, 0 rows affected (0.02 sec)mysql> desc t6; +-------+-----------+------+-----+-------------------+-----------------------------+ | Field | Type | Null | Key | Default | Extra | +-------+-----------+------+-----+-------------------+-----------------------------+ | t1 | timestamp | NO | | CURRENT_TIMESTAMP | on update CURRENT_TIMESTAMP | +-------+-----------+------+-----+-------------------+-----------------------------+ 1 row in set (0.01 sec)mysql> insert into t6 values (19700101080001); Query OK, 1 row affected (0.00 sec)mysql> select * from t6; +---------------------+ | t1 | +---------------------+ | 1970-01-01 08:00:01 | +---------------------+ 1 row in set (0.00 sec) # timestamp时间的下限是19700101080001 mysql> insert into t6 values (19700101080000); ERROR 1292 (22007): Incorrect datetime value: '19700101080000' for column 't1' at row 1mysql> insert into t6 values ('2038-01-19 11:14:07'); Query OK, 1 row affected (0.00 sec) # timestamp时间的上限是2038-01-19 11:14:07 mysql> insert into t6 values ('2038-01-19 11:14:08'); ERROR 1292 (22007): Incorrect datetime value: '2038-01-19 11:14:08' for column 't1' at row 1 mysql>
year实例
mysql> create table t7 (y year); Query OK, 0 rows affected (0.02 sec)mysql> insert into t7 values (2018); Query OK, 1 row affected (0.00 sec)mysql> select * from t7; +------+ | y | +------+ | 2018 | +------+ 1 row in set (0.00 sec)
datetime实例
mysql> create table t8 (dt datetime); Query OK, 0 rows affected (0.01 sec)mysql> insert into t8 values ('2018-9-26 12:20:10'); Query OK, 1 row affected (0.01 sec)mysql> insert into t8 values ('2018/9/26 12+20+10'); Query OK, 1 row affected (0.00 sec)mysql> insert into t8 values ('20180926122010'); Query OK, 1 row affected (0.00 sec)mysql> insert into t8 values (20180926122010); Query OK, 1 row affected (0.00 sec)mysql> select * from t8; +---------------------+ | dt | +---------------------+ | 2018-09-26 12:20:10 | | 2018-09-26 12:20:10 | | 2018-09-26 12:20:10 | | 2018-09-26 12:20:10 | +---------------------+ 4 rows in set (0.00 sec)
enum/set
enum 单选
set 多选
实例
mysql> create table t10 (name char(20),gender enum('female','male')); Query OK, 0 rows affected (0.01 sec)# 选择enum('female','male')中的一项作为gender的值,可以正常插入 mysql> insert into t10 values ('nezha','male'); Query OK, 1 row affected (0.00 sec)# 不能同时插入'male,female'两个值,也不能插入不属于'male,female'的值 mysql> insert into t10 values ('nezha','male,female'); ERROR 1265 (01000): Data truncated for column 'gender' at row 1mysql> create table t11 (name char(20),hobby set('抽烟','喝酒','烫头','翻车')); Query OK, 0 rows affected (0.01 sec)# 可以任意选择set('抽烟','喝酒','烫头','翻车')中的项,并自带去重功能 mysql> insert into t11 values ('yuan','烫头,喝酒,烫头'); Query OK, 1 row affected (0.01 sec)mysql> select * from t11; +------+---------------+ | name | hobby | +------+---------------+ | yuan | 喝酒,烫头 | +------+---------------+ 1 row in set (0.00 sec)# 不能选择不属于set('抽烟','喝酒','烫头','翻车')中的项, mysql> insert into t11 values ('alex','烫头,翻车,看妹子'); ERROR 1265 (01000): Data truncated for column 'hobby' at row 1
4)表的完整性约束
为了约束某一字段
分类
无符号的——
int unsigned
不能为空
- not null
- 实例:
mysql> create table t12 (id int not null); Query OK, 0 rows affected (0.02 sec)mysql> select * from t12; Empty set (0.00 sec)mysql> desc t12; +-------+---------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +-------+---------+------+-----+---------+-------+ | id | int(11) | NO | | NULL | | +-------+---------+------+-----+---------+-------+ 1 row in set (0.00 sec)#不能向id列插入空元素。 mysql> insert into t12 values (null); ERROR 1048 (23000): Column 'id' cannot be nullmysql> insert into t12 values (1); Query OK, 1 row affected (0.01 sec)
默认值
default
我们约束某一列不为空,如果这一列中经常有重复的内容,就需要我们频繁的插入,这样会给我们的操作带来新的负担,于是就出现了默认值的概念。默认值,创建列时可以指定默认值,当插入数据时如果未主动设置,则自动添加默认值
not null + default实例
mysql> create table t13 (id1 int not null,id2 int not null default 222); Query OK, 0 rows affected (0.01 sec)mysql> desc t13; +-------+---------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +-------+---------+------+-----+---------+-------+ | id1 | int(11) | NO | | NULL | | | id2 | int(11) | NO | | 222 | | +-------+---------+------+-----+---------+-------+ 2 rows in set (0.01 sec)# 只向id1字段添加值,会发现id2字段会使用默认值填充 mysql> insert into t13 (id1) values (111); Query OK, 1 row affected (0.00 sec)mysql> select * from t13; +-----+-----+ | id1 | id2 | +-----+-----+ | 111 | 222 | +-----+-----+ 1 row in set (0.00 sec)# id1字段不能为空,所以不能单独向id2字段填充值; mysql> insert into t13 (id2) values (223); ERROR 1364 (HY000): Field 'id1' doesn't have a default value# 向id1,id2中分别填充数据,id2的填充数据会覆盖默认值 mysql> insert into t13 (id1,id2) values (112,223); Query OK, 1 row affected (0.00 sec)mysql> select * from t13; +-----+-----+ | id1 | id2 | +-----+-----+ | 111 | 222 | | 112 | 223 | +-----+-----+ 2 rows in set (0.00 sec)
not null不生效实例
设置严格模式:不支持对not null字段插入null值不支持对自增长字段插入”值不支持text字段有默认值直接在mysql中生效(重启失效): mysql>set sql_mode="STRICT_TRANS_TABLES,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION";配置文件添加(永久失效): sql-mode="STRICT_TRANS_TABLES,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION"
唯一约束
unique
唯一约束,指定某列或者几列组合不能重复
unique实例
方法一: create table department1( id int, name varchar(20) unique, comment varchar(100) );方法二: create table department2( id int, name varchar(20), comment varchar(100), unique(name) );mysql> insert into department1 values(1,'IT','技术'); Query OK, 1 row affected (0.00 sec) mysql> insert into department1 values(1,'IT','技术'); ERROR 1062 (23000): Duplicate entry 'IT' for key 'name' mysql> insert into department1 values(1,'IT','技术'); # 注意:虽然name字段规定为唯一,但是可以插入多个唯一约束字段都为null的数据 mysql> insert into department1 values(2,null,'空1'); Query OK, 1 row affected (0.00 sec) mysql> insert into department1 values(3,null,'空2'); Query OK, 1 row affected (0.00 sec)
not null + unique实例
mysql> create table t1(id int not null unique); Query OK, 0 rows affected (0.02 sec)mysql> desc t1; +-------+---------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +-------+---------+------+-----+---------+-------+ | id | int(11) | NO | PRI | NULL | | +-------+---------+------+-----+---------+-------+ 1 row in set (0.00 sec)
联合唯一
create table service( id int primary key auto_increment, name varchar(20), host varchar(15) not null, port int not null, unique(host,port) #联合唯一 );mysql> insert into service values-> (1,'nginx','192.168.0.10',80),-> (2,'haproxy','192.168.0.20',80),-> (3,'mysql','192.168.0.30',3306)-> ; Query OK, 3 rows affected (0.01 sec) Records: 3 Duplicates: 0 Warnings: 0mysql> insert into service(name,host,port) values('nginx','192.168.0.10',80); ERROR 1062 (23000): Duplicate entry '192.168.0.10-80' for key 'host'
自增
概念
auto_increment
- 约束字段为自动增长,被约束的字段必须同时被key约束
- 只能对数字有效,自带非空约束
- 至少是unique的约束之后才能使用auto_increment
设置auto_increment实例
#不指定id,则自动增长 create table student( id int primary key auto_increment, name varchar(20), sex enum('male','female') default 'male' );mysql> desc student; +-------+-----------------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +-------+-----------------------+------+-----+---------+----------------+ | id | int(11) | NO | PRI | NULL | auto_increment | | name | varchar(20) | YES | | NULL | | | sex | enum('male','female') | YES | | male | | +-------+-----------------------+------+-----+---------+----------------+ mysql> insert into student(name) values-> ('egon'),-> ('alex')-> ;mysql> select * from student; +----+------+------+ | id | name | sex | +----+------+------+ | 1 | egon | male | | 2 | alex | male | +----+------+------+#也可以指定id mysql> insert into student values(4,'asb','female'); Query OK, 1 row affected (0.00 sec)mysql> insert into student values(7,'wsb','female'); Query OK, 1 row affected (0.00 sec)mysql> select * from student; +----+------+--------+ | id | name | sex | +----+------+--------+ | 1 | egon | male | | 2 | alex | male | | 4 | asb | female | | 7 | wsb | female | +----+------+--------+#对于自增的字段,在用delete删除后,再插入值,该字段仍按照删除前的位置继续增长 mysql> delete from student; Query OK, 4 rows affected (0.00 sec)mysql> select * from student; Empty set (0.00 sec)mysql> insert into student(name) values('ysb'); mysql> select * from student; +----+------+------+ | id | name | sex | +----+------+------+ | 8 | ysb | male | +----+------+------+#应该用truncate清空表,比起delete一条一条地删除记录,truncate是直接清空表,在删除大表时用它 mysql> truncate student; Query OK, 0 rows affected (0.01 sec)mysql> insert into student(name) values('egon'); Query OK, 1 row affected (0.01 sec)mysql> select * from student; +----+------+------+ | id | name | sex | +----+------+------+ | 1 | egon | male | +----+------+------+ row in set (0.00 sec)
offset偏移量
#在创建完表后,修改自增字段的起始值 mysql> create table student(-> id int primary key auto_increment,-> name varchar(20),-> sex enum('male','female') default 'male'-> );mysql> alter table student auto_increment=3;mysql> show create table student; ....... ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mysql> insert into student(name) values('egon'); Query OK, 1 row affected (0.01 sec)mysql> select * from student; +----+------+------+ | id | name | sex | +----+------+------+ | 3 | egon | male | +----+------+------+ row in set (0.00 sec)mysql> show create table student; ....... ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8#也可以创建表时指定auto_increment的初始值,注意初始值的设置为表选项,应该放到括号外 create table student( id int primary key auto_increment, name varchar(20), sex enum('male','female') default 'male' )auto_increment=3;#设置步长 sqlserver:自增步长基于表级别create table t1(id int。。。)engine=innodb,auto_increment=2 步长=2 default charset=utf8mysql自增的步长:show session variables like 'auto_inc%';#基于会话级别set session auth_increment_increment=2 #修改会话级别的步长#基于全局级别的set global auth_increment_increment=2 #修改全局级别的步长(所有会话都生效)#!!!注意了注意了注意了!!! If the value of auto_increment_offset is greater than that of auto_increment_increment, the value of auto_increment_offset is ignored. 翻译:如果auto_increment_offset的值大于auto_increment_increment的值,则auto_increment_offset的值会被忽略 ,这相当于第一步步子就迈大了,扯着了蛋 比如:设置auto_increment_offset=3,auto_increment_increment=2mysql> set global auto_increment_increment=5; Query OK, 0 rows affected (0.00 sec)mysql> set global auto_increment_offset=3; Query OK, 0 rows affected (0.00 sec)mysql> show variables like 'auto_incre%'; #需要退出重新登录 +--------------------------+-------+ | Variable_name | Value | +--------------------------+-------+ | auto_increment_increment | 1 | | auto_increment_offset | 1 | +--------------------------+-------+create table student( id int primary key auto_increment, name varchar(20), sex enum('male','female') default 'male' );mysql> insert into student(name) values('egon1'),('egon2'),('egon3'); mysql> select * from student; +----+-------+------+ | id | name | sex | +----+-------+------+ | 3 | egon1 | male | | 8 | egon2 | male | | 13 | egon3 | male | +----+-------+------+步长:auto_increment_increment,起始偏移量:auto_increment_offset
主键
概念
- 主键为了保证表中的每一条数据的该字段都是表格中的唯一值。换言之,它是用来独一无二地确认一个表格中的每一行数据。
- 主键可以包含一个字段或多个字段。当主键包含多个栏位时,称为组合键 (Composite Key),也可以叫联合主键。
- 主键可以在建置新表格时设定 (运用 CREATE TABLE 语句),或是以改变现有的表格架构方式设定 (运用 ALTER TABLE)。
- 主键必须唯一,主键值非空;可以是单一字段,也可以是多字段组合。
单字段主键
============单列做主键=============== #方法一:not null+unique(第一个这样定义的字段默认为主键) create table department1( id int not null unique, #主键 name varchar(20) not null unique, comment varchar(100) );mysql> desc department1; +---------+--------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +---------+--------------+------+-----+---------+-------+ | id | int(11) | NO | PRI | NULL | | | name | varchar(20) | NO | UNI | NULL | | | comment | varchar(100) | YES | | NULL | | +---------+--------------+------+-----+---------+-------+ rows in set (0.01 sec)#方法二:在某一个字段后用primary key create table department2( id int primary key, #主键 name varchar(20), comment varchar(100) );mysql> desc department2; +---------+--------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +---------+--------------+------+-----+---------+-------+ | id | int(11) | NO | PRI | NULL | | | name | varchar(20) | YES | | NULL | | | comment | varchar(100) | YES | | NULL | | +---------+--------------+------+-----+---------+-------+ rows in set (0.00 sec)#方法三:在所有字段后单独定义primary key create table department3( id int, name varchar(20), comment varchar(100), primary key(id); #创建主键并为其命名pk_namemysql> desc department3; +---------+--------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +---------+--------------+------+-----+---------+-------+ | id | int(11) | NO | PRI | NULL | | | name | varchar(20) | YES | | NULL | | | comment | varchar(100) | YES | | NULL | | +---------+--------------+------+-----+---------+-------+ rows in set (0.01 sec)# 方法四:给已经建成的表添加主键约束 mysql> create table department4(-> id int,-> name varchar(20),-> comment varchar(100)); Query OK, 0 rows affected (0.01 sec)mysql> desc department4; +---------+--------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +---------+--------------+------+-----+---------+-------+ | id | int(11) | YES | | NULL | | | name | varchar(20) | YES | | NULL | | | comment | varchar(100) | YES | | NULL | | +---------+--------------+------+-----+---------+-------+ 3 rows in set (0.01 sec)mysql> alter table department4 modify id int primary key; Query OK, 0 rows affected (0.02 sec) Records: 0 Duplicates: 0 Warnings: 0mysql> desc department4; +---------+--------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +---------+--------------+------+-----+---------+-------+ | id | int(11) | NO | PRI | NULL | | | name | varchar(20) | YES | | NULL | | | comment | varchar(100) | YES | | NULL | | +---------+--------------+------+-----+---------+-------+ 3 rows in set (0.01 sec)
多字段主键(联合主键)
==================多列做主键================ # 写法1 create table service( ip varchar(15), port char(5), service_name varchar(10) not null, primary key(ip,port) # 联合主键的两个字段default为''(空字符串) ); # 写法2 create table service( ip varchar(15) not null, port char(5) not null, service_name varchar(10) not null, unique(ip,port) );mysql> desc service; +--------------+-------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +--------------+-------------+------+-----+---------+-------+ | ip | varchar(15) | NO | PRI | NULL | | | port | char(5) | NO | PRI | NULL | | | service_name | varchar(10) | NO | | NULL | | +--------------+-------------+------+-----+---------+-------+ 3 rows in set (0.00 sec)mysql> insert into service values-> ('172.16.45.10','3306','mysqld'),-> ('172.16.45.11','3306','mariadb')-> ; Query OK, 2 rows affected (0.00 sec) Records: 2 Duplicates: 0 Warnings: 0mysql> insert into service values ('172.16.45.10','3306','nginx'); ERROR 1062 (23000): Duplicate entry '172.16.45.10-3306' for key 'PRIMARY'
外键
两张表之间设置关联
Foreign key(自己的字段) references 外表(外表字段)
创建外键的条件
mysql> create table departments (dep_id int(4),dep_name varchar(11)); Query OK, 0 rows affected (0.02 sec)mysql> desc departments; +----------+-------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +----------+-------------+------+-----+---------+-------+ | dep_id | int(4) | YES | | NULL | | | dep_name | varchar(11) | YES | | NULL | | +----------+-------------+------+-----+---------+-------+ 2 rows in set (0.00 sec)# 创建外键不成功 mysql> create table staff_info (s_id int,name varchar(20),dep_id int,foreign key(dep_id) references departments(dep_id)); ERROR 1215 (HY000): Cannot add foreign key # 设置dep_id非空,仍然不能成功创建外键 mysql> alter table departments modify dep_id int(4) not null; Query OK, 0 rows affected (0.02 sec) Records: 0 Duplicates: 0 Warnings: 0mysql> desc departments; +----------+-------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +----------+-------------+------+-----+---------+-------+ | dep_id | int(4) | NO | | NULL | | | dep_name | varchar(11) | YES | | NULL | | +----------+-------------+------+-----+---------+-------+ 2 rows in set (0.00 sec)mysql> create table staff_info (s_id int,name varchar(20),dep_id int,foreign key(dep_id) references departments(dep_id)); ERROR 1215 (HY000): Cannot add foreign key constraint# 当设置字段为unique唯一字段时,设置该字段为外键成功 mysql> alter table departments modify dep_id int(4) unique; Query OK, 0 rows affected (0.01 sec) Records: 0 Duplicates: 0 Warnings: 0mysql> desc departments; +----------+-------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +----------+-------------+------+-----+---------+-------+ | dep_id | int(4) | YES | UNI | NULL | | | dep_name | varchar(11) | YES | | NULL | | +----------+-------------+------+-----+---------+-------+ 2 rows in set (0.01 sec)mysql> create table staff_info (s_id int,name varchar(20),dep_id int,foreign key(dep_id) references departments(dep_id)); Query OK, 0 rows affected (0.02 sec)
外键操作实例
#表类型必须是innodb存储引擎,且被关联的字段,即references指定的另外一个表的字段,必须保证唯一 create table department( id int primary key, name varchar(20) not null )engine=innodb;#dpt_id外键,关联父表(department主键id),同步更新,同步删除 create table employee( id int primary key, name varchar(20) not null, dpt_id int, foreign key(dpt_id) references department(id) on delete cascade # 级连删除 on update cascade # 级连更新 )engine=innodb;#先往父表department中插入记录 insert into department values (1,'教质部'), (2,'技术部'), (3,'人力资源部');#再往子表employee中插入记录 insert into employee values (1,'yuan',1), (2,'nezha',2), (3,'egon',2), (4,'alex',2), (5,'wusir',3), (6,'李沁洋',3), (7,'皮卡丘',3), (8,'程咬金',3), (9,'程咬银',3) ;#删父表department,子表employee中对应的记录跟着删 mysql> delete from department where id=2; Query OK, 1 row affected (0.00 sec)mysql> select * from employee; +----+-----------+--------+ | id | name | dpt_id | +----+-----------+--------+ | 1 | yuan | 1 | | 5 | wusir | 3 | | 6 | 李沁洋 | 3 | | 7 | 皮卡丘 | 3 | | 8 | 程咬金 | 3 | | 9 | 程咬银 | 3 | +----+-----------+--------+ 6 rows in set (0.00 sec)#更新父表department,子表employee中对应的记录跟着改 mysql> update department set id=2 where id=3; Query OK, 1 row affected (0.01 sec) Rows matched: 1 Changed: 1 Warnings: 0mysql> select * from employee; +----+-----------+--------+ | id | name | dpt_id | +----+-----------+--------+ | 1 | yuan | 1 | | 5 | wusir | 2 | | 6 | 李沁洋 | 2 | | 7 | 皮卡丘 | 2 | | 8 | 程咬金 | 2 | | 9 | 程咬银 | 2 | +----+-----------+--------+ 6 rows in set (0.00 sec)
on delete实例
. cascade方式 在父表上update/delete记录时,同步update/delete掉子表的匹配记录 . set null方式 在父表上update/delete记录时,将子表上匹配记录的列设为null 要注意子表的外键列不能为not null . No action方式 如果子表中有匹配的记录,则不允许对父表对应候选键进行update/delete操作 . Restrict方式 同no action, 都是立即检查外键约束. Set default方式 父表有变更时,子表将外键列设置成一个默认的值 但Innodb不能识别# 班级表 # create table class( # cid int primary key auto_increment, # cname char(12) not null, # startd date # ) ''' # 学生表 create table stu(id int primary key auto_increment,name char(12) not null,gender enum('male','female') default 'male',class_id int,foreign key(class_id) references class(cid) ) '''# create table stu2( # id int primary key auto_increment, # name char(12) not null, # gender enum('male','female') default 'male', # class_id int, # foreign key(class_id) references class(cid) # on update cascade # on delete cascade # 尽量不用 # )
5)修改表结构
语法
语法: 1. 修改表名ALTER TABLE 表名 RENAME 新表名;2. 增加字段ALTER TABLE 表名ADD 字段名 数据类型 [完整性约束条件…],ADD 字段名 数据类型 [完整性约束条件…];3. 删除字段ALTER TABLE 表名 DROP 字段名;4. 修改字段ALTER TABLE 表名 MODIFY 字段名 数据类型 [完整性约束条件…];ALTER TABLE 表名 CHANGE 旧字段名 新字段名 旧数据类型 [完整性约束条件…];ALTER TABLE 表名 CHANGE 旧字段名 新字段名 新数据类型 [完整性约束条件…];5.修改字段排列顺序/在增加的时候指定字段位置ALTER TABLE 表名ADD 字段名 数据类型 [完整性约束条件…] FIRST;ALTER TABLE 表名ADD 字段名 数据类型 [完整性约束条件…] AFTER 字段名;ALTER TABLE 表名CHANGE 字段名 旧字段名 新字段名 新数据类型 [完整性约束条件…] FIRST;ALTER TABLE 表名MODIFY 字段名 数据类型 [完整性约束条件…] AFTER 字段名;
alter操作非空和唯一
create table t(id int unique,name char(10) not null);#去掉null约束 alter table t modify name char(10) null; # 添加null约束 alter table t modify name char(10) not null;# 去掉unique约束 alter table t drop index id; # 添加unique约束 alter table t modify id int unique;# 添加联合唯一 alter table t add unique index(aa,bb);
alter操作主键
1、首先创建一个数据表table_test: create table table_test( `id` varchar(100) NOT NULL, `name` varchar(100) NOT NULL, PRIMARY KEY (`name`) ); 2、如果发现主键设置错了,应该是id是主键,但如今表里已经有好多数据了,不能删除表再重建了,仅仅能在这基础上改动表结构。 先删除主键 alter table table_test drop primary key; 然后再增加主键 alter table table_test add primary key(id); 注:在增加主键之前,必须先把反复的id删除掉。
为表添加外键
创建press表 CREATE TABLE `press` (`id` int(11) NOT NULL,`name` char(10) DEFAULT NULL,PRIMARY KEY (`id`) ) ;创建book表 CREATE TABLE `book` (`id` int(11) DEFAULT NULL,`bk_name` char(12) DEFAULT NULL,`press_id` int(11) NOT NULL,KEY `press_id` (`press_id`) ) ;为book表添加外键 alter table book add constraint fk_id foreign key(press_id) references press(id);删除外键 alter table book drop foreign key fk_id;
实例
mysql> desc staff_info; +-------+-----------------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +-------+-----------------------+------+-----+---------+-------+ | id | int(11) | YES | | NULL | | | name | varchar(50) | YES | | NULL | | | age | int(3) | YES | | NULL | | | sex | enum('male','female') | YES | | NULL | | | phone | bigint(11) | YES | | NULL | | | job | varchar(11) | YES | | NULL | | +-------+-----------------------+------+-----+---------+-------+ 6 rows in set (0.00 sec)# 表重命名 mysql> alter table staff_info rename staff; Query OK, 0 rows affected (0.00 sec)mysql> desc staff; +-------+-----------------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +-------+-----------------------+------+-----+---------+-------+ | id | int(11) | YES | | NULL | | | name | varchar(50) | YES | | NULL | | | age | int(3) | YES | | NULL | | | sex | enum('male','female') | YES | | NULL | | | phone | bigint(11) | YES | | NULL | | | job | varchar(11) | YES | | NULL | | +-------+-----------------------+------+-----+---------+-------+ 6 rows in set (0.00 sec)# 删除sex列 mysql> alter table staff drop sex; Query OK, 0 rows affected (0.02 sec) Records: 0 Duplicates: 0 Warnings: 0mysql> desc staff; +-------+-------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +-------+-------------+------+-----+---------+-------+ | id | int(11) | YES | | NULL | | | name | varchar(50) | YES | | NULL | | | age | int(3) | YES | | NULL | | | phone | bigint(11) | YES | | NULL | | | job | varchar(11) | YES | | NULL | | +-------+-------------+------+-----+---------+-------+ 5 rows in set (0.01 sec)# 添加列 mysql> alter table staff add sex enum('male','female'); Query OK, 0 rows affected (0.03 sec) Records: 0 Duplicates: 0 Warnings: 0# 修改id的宽度 mysql> alter table staff modify id int(4); Query OK, 0 rows affected (0.02 sec) Records: 0 Duplicates: 0 Warnings: 0mysql> desc staff; +-------+-----------------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +-------+-----------------------+------+-----+---------+-------+ | id | int(4) | YES | | NULL | | | name | varchar(50) | YES | | NULL | | | age | int(3) | YES | | NULL | | | phone | bigint(11) | YES | | NULL | | | job | varchar(11) | YES | | NULL | | | sex | enum('male','female') | YES | | NULL | | +-------+-----------------------+------+-----+---------+-------+ 6 rows in set (0.01 sec)# 修改name列的字段名 mysql> alter table staff change name sname varchar(20); Query OK, 4 rows affected (0.03 sec) Records: 4 Duplicates: 0 Warnings: 0mysql> desc staff; +-------+-----------------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +-------+-----------------------+------+-----+---------+-------+ | id | int(4) | YES | | NULL | | | sname | varchar(20) | YES | | NULL | | | age | int(3) | YES | | NULL | | | phone | bigint(11) | YES | | NULL | | | job | varchar(11) | YES | | NULL | | | sex | enum('male','female') | YES | | NULL | | +-------+-----------------------+------+-----+---------+-------+ 6 rows in set (0.00 sec)# 修改sex列的位置 mysql> alter table staff modify sex enum('male','female') after sname; Query OK, 0 rows affected (0.02 sec) Records: 0 Duplicates: 0 Warnings: 0mysql> desc staff; +-------+-----------------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +-------+-----------------------+------+-----+---------+-------+ | id | int(4) | YES | | NULL | | | sname | varchar(20) | YES | | NULL | | | sex | enum('male','female') | YES | | NULL | | | age | int(3) | YES | | NULL | | | phone | bigint(11) | YES | | NULL | | | job | varchar(11) | YES | | NULL | | +-------+-----------------------+------+-----+---------+-------+ 6 rows in set (0.00 sec)# 创建自增id主键 mysql> alter table staff modify id int(4) primary key auto_increment; Query OK, 4 rows affected (0.02 sec) Records: 4 Duplicates: 0 Warnings: 0mysql> desc staff; +-------+-----------------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +-------+-----------------------+------+-----+---------+----------------+ | id | int(4) | NO | PRI | NULL | auto_increment | | sname | varchar(20) | YES | | NULL | | | sex | enum('male','female') | YES | | NULL | | | age | int(3) | YES | | NULL | | | phone | bigint(11) | YES | | NULL | | | job | varchar(11) | YES | | NULL | | +-------+-----------------------+------+-----+---------+----------------+ 6 rows in set (0.00 sec)# 删除主键,可以看到删除一个自增主键会报错 mysql> alter table staff drop primary key; ERROR 1075 (42000): Incorrect table definition; there can be only one auto column and it must be defined as a key# 需要先去掉主键的自增约束,然后再删除主键约束 mysql> alter table staff modify id int(11); Query OK, 4 rows affected (0.02 sec) Records: 4 Duplicates: 0 Warnings: 0mysql> desc staff; +-------+-----------------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +-------+-----------------------+------+-----+---------+-------+ | id | int(11) | NO | PRI | 0 | | | sname | varchar(20) | YES | | NULL | | | sex | enum('male','female') | YES | | NULL | | | age | int(3) | YES | | NULL | | | phone | bigint(11) | YES | | NULL | | | job | varchar(11) | YES | | NULL | | +-------+-----------------------+------+-----+---------+-------+ 6 rows in set (0.01 sec)mysql> alter table staff drop primary key; Query OK, 4 rows affected (0.06 sec) Records: 4 Duplicates: 0 Warnings: 0# 添加联合主键 mysql> alter table staff add primary key (sname,age); Query OK, 0 rows affected (0.02 sec) Records: 0 Duplicates: 0 Warnings: 0# 删除主键 mysql> alter table staff drop primary key; Query OK, 4 rows affected (0.02 sec) Records: 4 Duplicates: 0 Warnings: 0# 创建主键id mysql> alter table staff add primary key (id); Query OK, 0 rows affected (0.02 sec) Records: 0 Duplicates: 0 Warnings: 0mysql> desc staff; +-------+-----------------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +-------+-----------------------+------+-----+---------+-------+ | id | int(11) | NO | PRI | 0 | | | sname | varchar(20) | NO | | | | | sex | enum('male','female') | YES | | NULL | | | age | int(3) | NO | | 0 | | | phone | bigint(11) | YES | | NULL | | | job | varchar(11) | YES | | NULL | | +-------+-----------------------+------+-----+---------+-------+ 6 rows in set (0.00 sec)# 为主键添加自增属性 mysql> alter table staff modify id int(4) auto_increment; Query OK, 4 rows affected (0.02 sec) Records: 4 Duplicates: 0 Warnings: 0mysql> desc staff; +-------+-----------------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +-------+-----------------------+------+-----+---------+----------------+ | id | int(4) | NO | PRI | NULL | auto_increment | | sname | varchar(20) | NO | | | | | sex | enum('male','female') | YES | | NULL | | | age | int(3) | NO | | 0 | | | phone | bigint(11) | YES | | NULL | | | job | varchar(11) | YES | | NULL | | +-------+-----------------------+------+-----+---------+----------------+ 6 rows in set (0.00 sec)
6)多表结构的创建和分析
多对一
#一对多或称为多对一 三张表:出版社,作者信息,书一对多(或多对一):一个出版社可以出版多本书关联方式:foreign key
sql实例
=====================多对一===================== create table press( id int primary key auto_increment, name varchar(20) );create table book( id int primary key auto_increment, name varchar(20), press_id int not null, foreign key(press_id) references press(id) on delete cascade on update cascade );insert into press(name) values ('北京工业地雷出版社'), ('人民音乐不好听出版社'), ('知识产权没有用出版社') ;insert into book(name,press_id) values ('九阳神功',1), ('九阴真经',2), ('九阴白骨爪',2), ('独孤九剑',3), ('降龙十巴掌',2), ('葵花宝典',3) ;
其他实例
班级和学生 一个班级可以对应多个学生,但一个学生只能对应一个班级主机和机房 一个机房可以有多台主机,但是一个主机只能属于一个机房
多对多——创建第三张表(两个外键)
#多对多 三张表:出版社,作者信息,书多对多:一个作者可以写多本书,一本书也可以有多个作者,双向的一对多,即多对多关联方式:foreign key+一张新的表
sql实例
=====================多对多===================== create table author( id int primary key auto_increment, name varchar(20) );#这张表就存放作者表与书表的关系,即查询二者的关系查这表就可以了 create table author2book( id int not null unique auto_increment, author_id int not null, book_id int not null, constraint fk_author foreign key(author_id) references author(id) on delete cascade on update cascade, constraint fk_book foreign key(book_id) references book(id) on delete cascade on update cascade, primary key(author_id,book_id) );#插入四个作者,id依次排开 insert into author(name) values('egon'),('alex'),('yuanhao'),('wpq');#每个作者与自己的代表作如下 egon: 九阳神功 九阴真经 九阴白骨爪 独孤九剑 降龙十巴掌 葵花宝典 alex: 九阳神功 葵花宝典 yuanhao: 独孤九剑 降龙十巴掌 葵花宝典 wpq: 九阳神功insert into author2book(author_id,book_id) values (1,1), (1,2), (1,3), (1,4), (1,5), (1,6), (2,1), (2,6), (3,4), (3,5), (3,6), (4,1) ;
其他实例
服务和机器 一个服务可能被部署到多台机器上,一台机器上也可以部署多个服务学生和课程 一个学生可以选择多门课程,一门课程也可以被多个学生选择
一对一
#一对一 两张表:学生表和客户表一对一:一个学生是一个客户关联方式:foreign key+unique
sql实例
create table customer(-> id int primary key auto_increment,-> name varchar(20) not null,-> qq varchar(10) not null,-> phone char(16) not null-> );create table student(-> id int primary key auto_increment,-> class_name varchar(20) not null,-> customer_id int unique, #该字段一定要是唯一的-> foreign key(customer_id) references customer(id) #外键的字段一定要保证unique-> on delete cascade-> on update cascade-> );#增加客户 mysql> insert into customer(name,qq,phone) values-> ('韩蕾','31811231',13811341220),-> ('杨澜','123123123',15213146809),-> ('翁惠天','283818181',1867141331),-> ('杨宗河','283818181',1851143312),-> ('袁承明','888818181',1861243314),-> ('袁清','112312312',18811431230)mysql> #增加学生 mysql> insert into student(class_name,customer_id) values-> ('脱产1班',3),-> ('周末1期',4),-> ('周末1期',5)-> ;
其他实例
例一:一个用户只有一个博客用户表:id name1 egon2 alex3 wupeiqi博客表 fk+uniqueid url name_id1 xxxx 12 yyyy 33 zzz 2例二:一个管理员唯一对应一个用户用户表:id user password1 egon xxxx2 alex yyyy管理员表:fk+uniqueid user_id password1 1 xxxxx2 2 yyyyy
3 数据操作
1)插入数据
- 插入完整数据(顺序插入)
INSERT INTO 表名(字段1,字段2,字段3…字段n) VALUES(值1,值2,值3…值n);
INSERT INTO 表名 VALUES (值1,值2,值3…值n);
- 指定字段插入数据
INSERT INTO 表名(字段1,字段2,字段3…) VALUES (值1,值2,值3…);
- 插入多条记录
INSERT INTO 表名 VALUES (值1,值2,值3…值n), (值1,值2,值3…值n), (值1,值2,值3…值n);
- 插入查询结果
INSERT INTO 表名(字段1,字段2,字段3…字段n) SELECT (字段1,字段2,字段3…字段n) FROM 表2 WHERE …;
2)修改数据
语法
UPDATE 表名 SET字段1=值1,字段2=值2,WHERE CONDITION;
实例
UPDATE mysql.user SET password=password(‘123’) where user=’root’ and host=’localhost’;
3)删除数据
语法
- 删数据
DELETE FROM 表名 WHERE CONITION;
- 清空表
delete from 表;
- 会清空表,但不会清空自增字段的offset偏移量
truncate table 表;
- 清空表和自增字段的偏移量
实例
DELETE FROM mysql.user WHERE password=’’;
4)查询数据
单表查询
简单查询
语法:
- 最简单的select
- select * from 表;
- select 字段,… from 表;
- 重命名字段
- select 字段 as 新名字,… from 表;
- select 字段 新名字,… from 表;
- 去重
- select distinct 字段 from 表;
- select distinct age,sex from employee;
- 使用函数
- concat
- concat_ws
- 四则运算的
- select emp_name,salary12 from employee; 乘法
- select emp_name,salary12 as annual_salary from employee;
- 使用判断逻辑
- case when语句 相当于 if条件判断句
- 最简单的select
建表和数据准备
company.employee员工id id int 姓名 emp_name varchar性别 sex enum年龄 age int入职日期 hire_date date岗位 post varchar职位描述 post_comment varchar薪水 salary double办公室 office int部门编号 depart_id int#创建表 create table employee( id int not null unique auto_increment, emp_name varchar(20) not null, sex enum('male','female') not null default 'male', #大部分是男的 age int(3) unsigned not null default 28, hire_date date not null, post varchar(50), post_comment varchar(100), salary double(15,2), office int, #一个部门一个屋子 depart_id int );#查看表结构 mysql> desc employee; +--------------+-----------------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +--------------+-----------------------+------+-----+---------+----------------+ | id | int(11) | NO | PRI | NULL | auto_increment | | emp_name | varchar(20) | NO | | NULL | | | sex | enum('male','female') | NO | | male | | | age | int(3) unsigned | NO | | 28 | | | 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 | | +--------------+-----------------------+------+-----+---------+----------------+#插入记录 #三个部门:教学,销售,运营 insert into employee(emp_name,sex,age,hire_date,post,salary,office,depart_id) values ('egon','male',18,'20170301','老男孩驻沙河办事处外交大使',7300.33,401,1), #以下是教学部 ('alex','male',78,'20150302','teacher',1000000.31,401,1), ('wupeiqi','male',81,'20130305','teacher',8300,401,1), ('yuanhao','male',73,'20140701','teacher',3500,401,1), ('liwenzhou','male',28,'20121101','teacher',2100,401,1), ('jingliyang','female',18,'20110211','teacher',9000,401,1), ('jinxin','male',18,'19000301','teacher',30000,401,1), ('成龙','male',48,'20101111','teacher',10000,401,1),('歪歪','female',48,'20150311','sale',3000.13,402,2),#以下是销售部门 ('丫丫','female',38,'20101101','sale',2000.35,402,2), ('丁丁','female',18,'20110312','sale',1000.37,402,2), ('星星','female',18,'20160513','sale',3000.29,402,2), ('格格','female',28,'20170127','sale',4000.33,402,2),('张野','male',28,'20160311','operation',10000.13,403,3), #以下是运营部门 ('程咬金','male',18,'19970312','operation',20000,403,3), ('程咬银','female',18,'20130311','operation',19000,403,3), ('程咬铜','male',18,'20150411','operation',18000,403,3), ('程咬铁','female',18,'20140512','operation',17000,403,3) ;#ps:如果在windows系统中,插入中文字符,select的结果为空白,可以将所有字符编码统一设置成gbk准备表和记录
一些简单查询
#简单查询SELECT id,emp_name,sex,age,hire_date,post,post_comment,salary,office,depart_id FROM employee;SELECT * FROM employee;SELECT emp_name,salary FROM employee;#避免重复DISTINCTSELECT DISTINCT post FROM employee; #通过四则运算查询SELECT emp_name, salary*12 FROM employee;SELECT emp_name, salary*12 AS Annual_salary FROM employee;SELECT emp_name, salary*12 Annual_salary FROM employee;#定义显示格式CONCAT() 函数用于连接字符串SELECT CONCAT('姓名: ',emp_name,' 年薪: ', salary*12) AS Annual_salary FROM employee;CONCAT_WS() 第一个参数为分隔符SELECT CONCAT_WS(':',emp_name,salary*12) AS Annual_salary FROM employee;结合CASE语句:SELECT(CASEWHEN emp_name = 'jingliyang' THENemp_nameWHEN emp_name = 'alex' THENCONCAT(emp_name,'_BIGSB')ELSEconcat(emp_name, 'SB')END) as new_nameFROMemployee;
where约束
作用:筛选所有符合条件的行
分类:
- 比较运算符
- > < >= <= <> !=
- 范围
- between 10000 and 20000 要1w-2w之间的
- in (10000,20000) 只要10000或者20000的
- 模糊匹配
- like
- % 通配符 表示任意长度的任意内容
- _ 通配符 一个字符长度的任意内容
- regexp
- 只能匹配一些简单的,以什么开头/结尾之类的——’^a’,‘g$’
- like
- 逻辑运算
- not\and\or
- 比较运算符
实例
#1:单条件查询SELECT emp_name FROM employeeWHERE post='sale';#2:多条件查询SELECT emp_name,salary FROM employeeWHERE post='teacher' AND salary>10000;#3:关键字BETWEEN ANDSELECT emp_name,salary FROM employee WHERE salary BETWEEN 10000 AND 20000;SELECT emp_name,salary FROM employee WHERE salary NOT BETWEEN 10000 AND 20000;#4:关键字IS NULL(判断某个字段是否为NULL不能用等号,需要用IS)SELECT emp_name,post_comment FROM employee WHERE post_comment IS NULL;SELECT emp_name,post_comment FROM employee WHERE post_comment IS NOT NULL;SELECT emp_name,post_comment FROM employee WHERE post_comment=''; 注意''是空字符串,不是nullps:执行update employee set post_comment='' where id=2;再用上条查看,就会有结果了#5:关键字IN集合查询SELECT emp_name,salary FROM employee WHERE salary=3000 OR salary=3500 OR salary=4000 OR salary=9000 ;SELECT emp_name,salary FROM employee WHERE salary IN (3000,3500,4000,9000) ;SELECT emp_name,salary FROM employee WHERE salary NOT IN (3000,3500,4000,9000) ;#6:关键字LIKE模糊查询通配符’%’SELECT * FROM employee WHERE emp_name LIKE 'eg%';通配符’_’SELECT * FROM employee WHERE emp_name LIKE 'al__';
分组 group by
根据谁分组,可以求这个组的总人数,最大值,最小值,平均值,求和 但是这个求出来的值只是和分组字段对应,并不和分组中的其他任何数据对应,这个时候查出来的所有其他字段都不生效.
单独使用GROUP BY关键字分组SELECT post FROM employee GROUP BY post;注意:我们按照post字段分组,那么select查询的字段只能是post,想要获取组内的其他相关信息,需要借助函数GROUP BY关键字和GROUP_CONCAT()函数一起使用SELECT post,GROUP_CONCAT(emp_name) FROM employee GROUP BY post;#按照岗位分组,并查看组内成员名SELECT post,GROUP_CONCAT(emp_name) as emp_members FROM employee GROUP BY post;GROUP BY与聚合函数一起使用select post,count(id) as count from employee group by post;#按照岗位分组,并查看每个组有多少人
强调:如果我们用unique的字段作为分组的依据,则每一条记录自成一组,这种分组没有意义
多条记录之间的某个字段值相同,该字段通常用来作为分组的依据
聚合函数
count 求个数
max 求最大值
min 求最小值
sum 求和
avg 求平均
实例
示例:SELECT COUNT(*) FROM employee;SELECT COUNT(*) FROM employee WHERE depart_id=1;SELECT MAX(salary) FROM employee;SELECT MIN(salary) FROM employee;SELECT AVG(salary) FROM employee;SELECT SUM(salary) FROM employee;SELECT SUM(salary) FROM employee WHERE depart_id=3;
having过滤
特点
- 在having条件中可以使用聚合函数,在where中不行
- 适合去筛选符合条件的某一组数据,而不是某一行数据
- 先分组再过滤 : 求平均薪资大于xx的部门,求人数大于xx的性别,求大于xx人的年龄段
having与where区别
#!!!执行优先级从高到低:where > group by > having #1. Where 发生在分组group by之前,因而Where中可以有任意字段,但是绝对不能使用聚合函数。 #2. Having发生在分组group by之后,因而Having中可以使用分组的字段,无法直接取到其他字段,可以使用聚合函数
验证
mysql> select @@sql_mode; +--------------------+ | @@sql_mode | +--------------------+ | ONLY_FULL_GROUP_BY | +--------------------+ row in set (0.00 sec)mysql> select * from emp where salary > 100000; +----+------+------+-----+------------+---------+--------------+------------+--------+-----------+ | id | emp_name | sex | age | hire_date | post | post_comment | salary | office | depart_id | +----+------+------+-----+------------+---------+--------------+------------+--------+-----------+ | 2 | alex | male | 78 | 2015-03-02 | teacher | NULL | 1000000.31 | 401 | 1 | +----+------+------+-----+------------+---------+--------------+------------+--------+-----------+ row in set (0.00 sec)mysql> select post,group_concat(emp_name) from emp group by post having salary > 10000;#错误,分组后无法直接取到salary字段 ERROR 1054 (42S22): Unknown column 'salary' in 'having clause' mysql> select post,group_concat(emp_name) from emp group by post having avg(salary) > 10000; +-----------+-------------------------------------------------------+ | post | group_concat(emp_name) | +-----------+-------------------------------------------------------+ | operation | 程咬铁,程咬铜,程咬银,程咬金,张野 | | teacher | 成龙,jinxin,jingliyang,liwenzhou,yuanhao,wupeiqi,alex | +-----------+-------------------------------------------------------+ rows in set (0.00 sec)
ORDER BY 查询排序
默认是升序 asc
降序 desc
order by age ,salary desc——优先根据age从小到大排,在age相同的情况下,再根据薪资从大到小排
按单列排序SELECT * FROM employee ORDER BY salary;SELECT * FROM employee ORDER BY salary ASC;SELECT * FROM employee ORDER BY salary DESC;按多列排序:先按照age排序,如果年纪相同,则按照薪资排序SELECT * from employeeORDER BY age,salary DESC;
LIMIT 限制查询的记录数
limit m,n
- 从m+1项开始,取n项
- 如果不写m,m默认为0
limit n offset m——与limit m, n相同
实例
示例:SELECT * FROM employee ORDER BY salary DESC LIMIT 3; #默认初始位置为0 SELECT * FROM employee ORDER BY salary DESCLIMIT 0,5; #从第0开始,即先查询出第一条,然后包含这一条在内往后查5条SELECT * FROM employee ORDER BY salary DESCLIMIT 5,5; #从第5开始,即先查询出第6条,然后包含这一条在内往后查5条
使用正则表达式查询
SELECT * FROM employee WHERE emp_name REGEXP '^ale';SELECT * FROM employee WHERE emp_name REGEXP 'on$';SELECT * FROM employee WHERE emp_name REGEXP 'm{2}';小结:对字符串匹配的方式 WHERE emp_name = 'egon'; WHERE emp_name LIKE 'yua%'; WHERE emp_name REGEXP 'on$';
多表查询
连表查询
连表就是在两张表连接的时候创建一张大表,里面存放的是两张表的笛卡尔积,再根据条件进行筛选就可以了
表与表之间的连接方式
- 内连接
- 语法:inner join … on …
- 只连接匹配的行
- 外连接
- 左外连接
- 语法:left join … on …
- 优先显示左边的未匹配项,右表中对应项为null
- 右外连接
- 语法:right join … on …
- 优先显示右边的未匹配项,左表中对应项为null
- 全外连接
- 语法:左外连接 union 右外连接
- 两表的未匹配项都会被显示,另一个表中的对应项均为null
- 左外连接
- 内连接
建表和数据准备
#建表 create table department( id int, name varchar(20) );create table employee( id int primary key auto_increment, name varchar(20), sex enum('male','female') not null default 'male', age int, dep_id int );#插入数据 insert into department values (200,'技术'), (201,'人力资源'), (202,'销售'), (203,'运营');insert into employee(name,sex,age,dep_id) values ('egon','male',18,200), ('alex','female',48,201), ('wupeiqi','male',38,201), ('yuanhao','female',28,202), ('liwenzhou','male',18,200), ('jingliyang','female',18,204) ;#查看表结构和数据 mysql> desc department; +-------+-------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +-------+-------------+------+-----+---------+-------+ | id | int(11) | YES | | NULL | | | name | varchar(20) | YES | | NULL | | +-------+-------------+------+-----+---------+-------+mysql> desc employee; +--------+-----------------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +--------+-----------------------+------+-----+---------+----------------+ | id | int(11) | NO | PRI | NULL | auto_increment | | name | varchar(20) | YES | | NULL | | | sex | enum('male','female') | NO | | male | | | age | int(11) | YES | | NULL | | | dep_id | int(11) | YES | | NULL | | +--------+-----------------------+------+-----+---------+----------------+mysql> select * from department; +------+--------------+ | id | name | +------+--------------+ | 200 | 技术 | | 201 | 人力资源 | | 202 | 销售 | | 203 | 运营 | +------+--------------+mysql> select * from employee; +----+------------+--------+------+--------+ | id | name | sex | age | dep_id | +----+------------+--------+------+--------+ | 1 | egon | male | 18 | 200 | | 2 | alex | female | 48 | 201 | | 3 | wupeiqi | male | 38 | 201 | | 4 | yuanhao | female | 28 | 202 | | 5 | liwenzhou | male | 18 | 200 | | 6 | jingliyang | female | 18 | 204 | +----+------------+--------+------+--------+表department与employee
交叉连接实例
mysql> select * from employee,department; +----+------------+--------+------+--------+------+--------------+ | id | name | sex | age | dep_id | id | name | +----+------------+--------+------+--------+------+--------------+ | 1 | egon | male | 18 | 200 | 200 | 技术 | | 1 | egon | male | 18 | 200 | 201 | 人力资源 | | 1 | egon | male | 18 | 200 | 202 | 销售 | | 1 | egon | male | 18 | 200 | 203 | 运营 | | 2 | alex | female | 48 | 201 | 200 | 技术 | | 2 | alex | female | 48 | 201 | 201 | 人力资源 | | 2 | alex | female | 48 | 201 | 202 | 销售 | | 2 | alex | female | 48 | 201 | 203 | 运营 | | 3 | wupeiqi | male | 38 | 201 | 200 | 技术 | | 3 | wupeiqi | male | 38 | 201 | 201 | 人力资源 | | 3 | wupeiqi | male | 38 | 201 | 202 | 销售 | | 3 | wupeiqi | male | 38 | 201 | 203 | 运营 | | 4 | yuanhao | female | 28 | 202 | 200 | 技术 | | 4 | yuanhao | female | 28 | 202 | 201 | 人力资源 | | 4 | yuanhao | female | 28 | 202 | 202 | 销售 | | 4 | yuanhao | female | 28 | 202 | 203 | 运营 | | 5 | liwenzhou | male | 18 | 200 | 200 | 技术 | | 5 | liwenzhou | male | 18 | 200 | 201 | 人力资源 | | 5 | liwenzhou | male | 18 | 200 | 202 | 销售 | | 5 | liwenzhou | male | 18 | 200 | 203 | 运营 | | 6 | jingliyang | female | 18 | 204 | 200 | 技术 | | 6 | jingliyang | female | 18 | 204 | 201 | 人力资源 | | 6 | jingliyang | female | 18 | 204 | 202 | 销售 | | 6 | jingliyang | female | 18 | 204 | 203 | 运营 | +----+------------+--------+------+--------+------+--------------+
内连接实例
#找两张表共有的部分,相当于利用条件从笛卡尔积结果中筛选出了正确的结果 #department没有204这个部门,因而employee表中关于204这条员工信息没有匹配出来 mysql> select employee.id,employee.name,employee.age,employee.sex,department.name from employee inner join department on employee.dep_id=department.id; +----+-----------+------+--------+--------------+ | id | name | age | sex | name | +----+-----------+------+--------+--------------+ | 1 | egon | 18 | male | 技术 | | 2 | alex | 48 | female | 人力资源 | | 3 | wupeiqi | 38 | male | 人力资源 | | 4 | yuanhao | 28 | female | 销售 | | 5 | liwenzhou | 18 | male | 技术 | +----+-----------+------+--------+--------------+#上述sql等同于 mysql> select employee.id,employee.name,employee.age,employee.sex,department.name from employee,department where employee.dep_id=department.id;
左连接实例
#以左表为准,即找出所有员工信息,当然包括没有部门的员工 #本质就是:在内连接的基础上增加左边有右边没有的结果 mysql> select employee.id,employee.name,department.name as depart_name from employee left join department on employee.dep_id=department.id; +----+------------+--------------+ | id | name | depart_name | +----+------------+--------------+ | 1 | egon | 技术 | | 5 | liwenzhou | 技术 | | 2 | alex | 人力资源 | | 3 | wupeiqi | 人力资源 | | 4 | yuanhao | 销售 | | 6 | jingliyang | NULL | +----+------------+--------------+
右连接实例
#以右表为准,即找出所有部门信息,包括没有员工的部门 #本质就是:在内连接的基础上增加右边有左边没有的结果 mysql> select employee.id,employee.name,department.name as depart_name from employee right join department on employee.dep_id=department.id; +------+-----------+--------------+ | id | name | depart_name | +------+-----------+--------------+ | 1 | egon | 技术 | | 2 | alex | 人力资源 | | 3 | wupeiqi | 人力资源 | | 4 | yuanhao | 销售 | | 5 | liwenzhou | 技术 | | NULL | NULL | 运营 | +------+-----------+--------------+
全外连接实例
全外连接:在内连接的基础上增加左边有右边没有的和右边有左边没有的结果 #注意:mysql不支持全外连接 full JOIN #强调:mysql可以使用此种方式间接实现全外连接 select * from employee left join department on employee.dep_id = department.id union select * from employee right join department on employee.dep_id = department.id ; #查看结果 +------+------------+--------+------+--------+------+--------------+ | id | name | sex | age | dep_id | id | name | +------+------------+--------+------+--------+------+--------------+ | 1 | egon | male | 18 | 200 | 200 | 技术 | | 5 | liwenzhou | male | 18 | 200 | 200 | 技术 | | 2 | alex | female | 48 | 201 | 201 | 人力资源 | | 3 | wupeiqi | male | 38 | 201 | 201 | 人力资源 | | 4 | yuanhao | female | 28 | 202 | 202 | 销售 | | 6 | jingliyang | female | 18 | 204 | NULL | NULL | | NULL | NULL | NULL | NULL | NULL | 203 | 运营 | +------+------------+--------+------+--------+------+--------------+#注意 union与union all的区别:union会去掉相同的纪录
符合条件连接查询
#示例1:以内连接的方式查询employee和department表,并且employee表中的age字段值必须大于25,即找出年龄大于25岁的员工以及员工所在的部门 select employee.name,department.name from employee inner join departmenton employee.dep_id = department.idwhere age > 25;#示例2:以内连接的方式查询employee和department表,并且以age字段的升序方式显示 select employee.id,employee.name,employee.age,department.name from employee,departmentwhere employee.dep_id = department.idand age > 25order by age asc;
子查询
特点:
- 子查询是将一个查询语句嵌套在另一个查询语句中。
- 内层查询语句的查询结果,可以为外层查询语句提供查询条件。
- 子查询中可以包含:IN、NOT IN、ANY、ALL、EXISTS 和 NOT EXISTS等关键字
- 还可以包含比较运算符:= 、 !=、> 、<等
带IN关键字的子查询
#查询平均年龄在25岁以上的部门名 select id,name from departmentwhere id in (select dep_id from employee group by dep_id having avg(age) > 25);#查看技术部员工姓名 select name from employeewhere dep_id in (select id from department where name='技术');#查看不足1人的部门名(子查询得到的是有人的部门id) select name from department where id not in (select distinct dep_id from employee);
带比较运算符的子查询
#比较运算符:=、!=、>、>=、<、<=、<> #查询大于所有人平均年龄的员工名与年龄 mysql> select name,age from emp where age > (select avg(age) from emp); +---------+------+ | name | age | +---------+------+ | alex | 48 | | wupeiqi | 38 | +---------+------+ 2 rows in set (0.00 sec)#查询大于部门内平均年龄的员工名、年龄 select t1.name,t1.age from emp t1 inner join (select dep_id,avg(age) avg_age from emp group by dep_id) t2 on t1.dep_id = t2.dep_id where t1.age > t2.avg_age;
带exists关键字的子查询
#department表中存在dept_id=203,Ture mysql> select * from employee-> where exists-> (select id from department where id=200); +----+------------+--------+------+--------+ | id | name | sex | age | dep_id | +----+------------+--------+------+--------+ | 1 | egon | male | 18 | 200 | | 2 | alex | female | 48 | 201 | | 3 | wupeiqi | male | 38 | 201 | | 4 | yuanhao | female | 28 | 202 | | 5 | liwenzhou | male | 18 | 200 | | 6 | jingliyang | female | 18 | 204 | +----+------------+--------+------+--------+#department表中存在dept_id=205,False mysql> select * from employee-> where exists-> (select id from department where id=204); Empty set (0.00 sec)
如果一个查询既可以使用连表查询,又可以使用子查询,此时推荐连表查询,因为效率高
4 mysql 索引
mysql索引原理参考博客
1)索引原理
数据准备
读取一次硬盘的时间开销
- 读取一次磁盘的开销极其大
- 磁盘的预读性原理:假如你需要10字节数据,那么硬盘就会认为那10字节数据的下一块内容也很快就会被用到。所以每一次读取硬盘的单位不是你要多少就读多少,每一次读取的数据块的大小都是固定的,4096个字节 - block块,会将你想要读的数据之后的下一个数据也读取出来,这就称为磁盘的预读性。
2)索引的数据结构——树
基本概念:
- 根节点
- 分支节 branch
- 点
- 叶子节点
- 二叉树
- b树
- 平衡树(btree-balance tree) 能够让查找某一个值经历的查找速度尽量平衡
- b+树
- 平衡树(btree-balance tree) 能够让查找某一个值经历的查找速度尽量平衡
- 分支节点不存储数据 – 让树的高度尽量矮,让查找一个数据的效率尽量的稳定
- 在所有叶子结点之间加入了双向的地址链接 – 查找范围非常快
mysql中存储数据的两种方式
- 聚集(簇)索引
- Innodb 必有且仅有一个 :主键
- 非聚集(簇)索引(辅助索引)
- innodb(非主键)
- myisam
- 聚集(簇)索引
索引的创建和删除
创建主键 primary key 聚集索引
创建唯一约束 unique 辅助索引
添加一个普通索引
#方法一:创建表时CREATE TABLE 表名 (字段名1 数据类型 [完整性约束条件…],字段名2 数据类型 [完整性约束条件…],[UNIQUE | FULLTEXT | SPATIAL ] INDEX | KEY[索引名] (字段名[(长度)] [ASC |DESC]) );#方法二:CREATE在已存在的表上创建索引CREATE [UNIQUE | FULLTEXT | SPATIAL ] INDEX 索引名 ON 表名 (字段名[(长度)] [ASC |DESC]) ;#方法三:ALTER TABLE在已存在的表上创建索引ALTER TABLE 表名 ADD [UNIQUE | FULLTEXT | SPATIAL ] INDEX索引名 (字段名[(长度)] [ASC |DESC]) ;#删除索引:DROP INDEX 索引名 ON 表名字;
正确使用索引
- 数据库使用的时候有什么注意事项
- 从搭建数据库的角度上来描述问题
- 建表的角度上
- 合理安排表关系
- 尽量把固定长度的字段放在前面
- 尽量使用char代替varchar
- 分表: 水平分,垂直分
- 使用sql语句的时候
- 尽量用where来约束数据范围到一个比较小的程度,比如说分页的时候
- 尽量使用连表查询而不是子查询
- 删除数据或者修改数据的时候尽量要用主键作为条件
- 合理的创建和使用索引
- 查询的条件字段不是索引字段——对哪一个字段创建了索引,就用这个字段做条件查询
- 在创建索引的时候应该对区分度比较大的列进行创建——1/10以下的重复率比较适合创建索引
- 范围
- 范围越大越慢
- 范围越小越快
- like ‘a%’ 快
- like ‘%a’ 慢
- 条件列参与计算/使用函数
- and和or
- id name
- select * from s1 where id = 1800000 and name = ‘eva’;
- select count(*) from s1 where id = 1800000 or name = ‘eva’;
- 多个条件的组合,如果使用and连接——其中一列含有索引,都可以加快查找速度
- 如果使用or连接——必须所有的列都含有索引,才能加快查找速度
- 联合索引 : 最左前缀原则(必须带着最左边的列做条件,从出现范围开始整条索引失效)
(id,name,email)
select * from s1 where id = 1800000 and name = ‘eva’ and email = ‘eva1800000@oldboy’;
select * from s1 where id = 1800000 and name = ‘eva’;
select * from s1 where id = 1800000 and email = ‘eva1800000@oldboy’;
select * from s1 where id = 1800000;
select * from s1 where name = ‘eva’ and email = ‘eva1800000@oldboy’;
(email,id,name)
select * from s1 where id >10000 and email = ‘eva1800000@oldboy’; - 条件中写出来的数据类型必须和定义的数据类型一致
- select * from biao where name = 666 # 不一致
- select的字段应该包含order by的字段
- select name,age from 表 order by age; # 比较好
- select name from 表 order by age; # 比较差
- 数据库使用的时候有什么注意事项
5 pymysql
1)python操作mysql数据库
操作步骤
- 连接数据库
- 获取游标
- 执行sql(增删改查)
- 如果涉及到修改:提交
- 关闭游标
- 关闭库
连接
基本连接
import pymysqldb = pymysql.connect("数据库ip","用户","密码","数据库" ) # 打开数据库连接 cur = conn.cursor() # 查询返回值为元组形式(值,...,值}) cur.execute("SELECT VERSION()") # 使用 execute() 方法执行 SQL 查询 data = cur.fetchone() # 使用 fetchone() 方法获取单条数据 print ("Database version : %s " % data) db.close()
更多参数
import pymysqlconn = pymysql.connect(host='localhost', user='root', password="root",database='db', port=3306, charset='utf-8', ) cur cur = conn.cursor(cursor=pymysql.cursors.DictCursor) # 查询返回值为字典形式{字段:值,...,字段:值}
创建表操作
import pymysql# 打开数据库连接 db = pymysql.connect("localhost","testuser","test123","TESTDB" )# 使用 cursor() 方法创建一个游标对象 cursor cursor = db.cursor()# 使用 execute() 方法执行 SQL,如果表存在则删除 cursor.execute("DROP TABLE IF EXISTS EMPLOYEE")# 使用预处理语句创建表 sql = """CREATE TABLE EMPLOYEE (FIRST_NAME CHAR(20) NOT NULL,LAST_NAME CHAR(20),AGE INT, SEX CHAR(1),INCOME FLOAT )"""cursor.execute(sql)# 关闭数据库连接 db.close()
操作数据
查询
Python查询Mysql使用 fetchone() 方法获取单条数据, 使用fetchall() 方法获取多条数据。
- fetchone(): 该方法获取下一个查询结果集。结果集是一个对象
- fetchall(): 接收全部的返回结果行.
- rowcount: 这是一个只读属性,并返回执行execute()方法后影响的行数。
实例1
import pymysql conn = pymysql.connect(host='127.0.0.1',user='root',password="123",database='homework') cur = conn.cursor(cursor=pymysql.cursors.DictCursor) # 查询返回字典 cur = conn.cursor() # cursor游标 cur.execute('select * from student;') print(cur.rowcount) # 获取查出多少行,便于使用fetchone取所有结果(可改成生成器节省内存) for i in range(cur.rowcount):ret = cur.fetchone() # 获取一条结果print(ret) cur.close() conn.close()
实例2
import pymysql conn = pymysql.connect(host='127.0.0.1',user='root',password="123",database='homework') cur = conn.cursor(cursor=pymysql.cursors.DictCursor) # 查询返回字典 cur = conn.cursor() # cursor游标 try:cur.execute('select * from student;')ret = cur.fetchone() # 获取一条结果print(ret)ret2 = cur.fetchmany(10) # 获取多条结果print(ret2)ret3 = cur.fetchall() # 获取全部结果print(ret3) except pymysql.err.ProgrammingError as e: # 出错处理打印出错信息print(e) cur.close() conn.close()
插入
第一种
import pymysql# 打开数据库连接 db = pymysql.connect("localhost","testuser","test123","TESTDB" )# 使用cursor()方法获取操作游标 cursor = db.cursor()# SQL 插入语句 sql = """INSERT INTO EMPLOYEE(FIRST_NAME,LAST_NAME, AGE, SEX, INCOME)VALUES ('Mac', 'Mohan', 20, 'M', 2000)""" try:cursor.execute(sql) # 执行sql语句db.commit() # 提交到数据库执行 except:db.rollback() # 如果发生错误则回滚# 关闭数据库连接 db.close()
第二种
import pymysql# 打开数据库连接 db = pymysql.connect("localhost","testuser","test123","TESTDB" )# 使用cursor()方法获取操作游标 cursor = db.cursor()# SQL 插入语句 sql = "INSERT INTO EMPLOYEE(FIRST_NAME, \LAST_NAME, AGE, SEX, INCOME) \VALUES (%s, %s, %s, %s, %s )" % \('Mac', 'Mohan', 20, 'M', 2000) try:cursor.execute(sql) # 执行sql语句db.commit() # 执行sql语句 except:db.rollback() # 发生错误时回滚# 关闭数据库连接 db.close()
删除
import pymysql# 打开数据库连接 db = pymysql.connect("localhost","testuser","test123","TESTDB" )# 使用cursor()方法获取操作游标 cursor = db.cursor()# SQL 删除语句 sql = "DELETE FROM EMPLOYEE WHERE AGE > %s" % (20) trycursor.execute(sql) # 执行SQL语句db.commit() # 提交修改 exceptdb.rollback() # 发生错误时回滚# 关闭连接 db.close()
更新
import pymysql# 打开数据库连接 db = pymysql.connect("localhost","testuser","test123","TESTDB" )# 使用cursor()方法获取操作游标 cursor = db.cursor()# SQL 更新语句 sql = "UPDATE EMPLOYEE SET AGE = AGE + 1 WHERE SEX = '%c'" % ('M') try:cursor.execute(sql) # 执行SQL语句db.commit() # 提交到数据库执行 exceptdb.rollback() # 发生错误时回滚# 关闭数据库连接 db.close()
2)sql注入
sql注入问题
在实际应用中需要向sql语句传参时,使用正常字符串传参方法**(’ sql “%s” 语句’ % v),此时会有一个漏洞,若传入的数据为“v";–”形式**,会不执行sql语句的后面那部分(即上述’语句‘部分),因为**–在sql语句中代表注释,将会注释掉sql语句的后面部分**,这种错误被称为:sql注入问题
错误示例
结合数据库 和python 写一个登录 user = input('username :') pwd = input('password :') conn = pymysql.connect(host='127.0.0.1',user='root',password="123",database='day42') sql = 'select * from userinfo where user = %s and password = %s' cur = conn.cursor() cur.execute(sql,(user,pwd)) print(cur.fetchone())# sql注入 select * from userinfo where user = "1869" or 1=1;-- " and password = "3714"; # 此时只要账户名正确无论密码是否正确都可以成功读取数据,严重bug
解决方法
传参数通过execute方法来传
同上数据更新改进实例
import pymysql# 打开数据库连接 db = pymysql.connect("localhost","testuser","test123","TESTDB" )# 使用cursor()方法获取操作游标 cursor = db.cursor()# SQL 更新语句 sql = "UPDATE EMPLOYEE SET AGE = AGE + 1 WHERE SEX = %c" try:cursor.execute(sql, ('M',)) # 传参时注意是元组传入,此时便避免了sql注入问题db.commit() # 提交到数据库执行 exceptdb.rollback() # 发生错误时回滚# 关闭数据库连接 db.close()
6 mysql的库/表备份与恢复
1)备份
#语法:
# mysqldump -h 服务器 -u用户名 -p密码 数据库名 > 备份文件.sql#示例:
#单库备份
mysqldump -uroot -p123 db1 > db1.sql
mysqldump -uroot -p123 db1 table1 table2 > db1-table1-table2.sql#多库备份
mysqldump -uroot -p123 --databases db1 db2 mysql db3 > db1_db2_mysql_db3.sql#备份所有库
mysqldump -uroot -p123 --all-databases > all.sql
2)恢复
#方法一:
[root@egon backup]# mysql -uroot -p123 < /backup/all.sql#方法二:
mysql> use db1;
mysql> SET SQL_LOG_BIN=0; #关闭二进制日志,只对当前session生效
mysql> source /root/db1.sql
7 事务/锁
begin; # 开启事务
select * from emp where id = 1 for update; # 查询id值,for update添加行锁;
update emp set salary=10000 where id = 1; # 完成更新
commit; # 提交事务
此文为个人学习old_boy系列课程笔记
参考博客(数据库部分)链接
5.15 mysql 数据库(数据库/表操作/索引/pymysql/备份与恢复/事务/锁) 学习笔记相关推荐
- mysql回表查询uuid_MySQL数据库回表与索引
[TOC] 回表的概念 先得出结论,根据下面的实验.如果我要获得['liu','25']这条记录.需要什么步骤. 1.先通过['liu']记录对应到普通索引index(name),获取到主键id:4. ...
- 2021年大数据Hive(三):手把手教你如何吃透Hive数据库和表操作(学会秒变数仓大佬)
全网最详细的Hive文章系列,强烈建议收藏加关注! 后面更新文章都会列出历史文章目录,帮助大家回顾知识重点. 目录 系列历史文章 前言 Hive数据库和表操作 一.数据库操作 1.创建数据库 2.创建 ...
- 创建数据库、表以及索引
创建数据库.表以及索引 创建数据库 这样做就可以创建一个数据库: CREATE DATABASE 数据库名称 创建一个表 这样做就可以创建一个数据库中的表: CREATE TABLE 表名称 ( 列名 ...
- 【数据库原理实验(openGauss)】创建数据库、表和索引
创建数据库.表和索引 文章目录 创建数据库.表和索引 一.创建数据库 二.创建与删除模式 三.创建与修改表 (1)创建表 (2)修改表 四.创建与删除索引 (1)创建索引 (2)删除索引 一.创建数据 ...
- 深度解析串行并发并行,开发人员需彻底搞懂丨mysql|redis|skynet|协程|索引|读写分离|分布式锁|主从同步
深度解析串行并发并行,开发人员需彻底搞懂 视频讲解如下,点击观看: 深度解析串行并发并行,开发人员需彻底搞懂丨mysql|redis|skynet|协程|索引|读写分离|分布式锁|主从同步丨C/C++ ...
- 算法学习 (门徒计划)3-2 哈希表与布隆过滤器及经典问题 学习笔记
算法学习 (门徒计划)3-2 哈希表与布隆过滤器及经典问题 学习笔记 前言 哈希表 哈希操作 冲突处理 开放定址法 再哈希法 公共溢出区 链式地址法 扩容哈希表 设计简易哈希表 总结 布隆过滤器 对比 ...
- python word 操作 doc 文件格式转docx 格式 学习笔记
python word 操作 doc 文件格式转docx 格式 学习笔记 from win32com import client as wc import time # TODO file_0 = & ...
- mysql数据库、表、索引、触发器
ctrl +c退出sql程序 1.数据库 查看数据库:show databases: 创建数据库:create database tb_name; 删除数据库:drop database db_nam ...
- 【MySQL数据库开发之三】MySQL 获得数据库和表操作!
通过上一篇的介绍,大家可以创建自己的数据库和表以及插入表中数据等等,本章继续介绍更多的数据库的相关操作: 1. 查看所有表单数据:(这里我直接使用上一篇创建的himiDB数据库与其中的peopl ...
最新文章
- 网络视频会议整体解决方案
- PHP-代码审计-ini配置文件
- 高可用系统架构设计 技术方案
- Oracle plsql 打包
- 使用AppFabric 承载WCF和WF服务-安装和使用
- 剖析Disruptor:为什么会这么快?(二)神奇的缓存行填充
- 探秘中国网购的数据迷城
- 虚拟机Centos系统安装
- 【转载】P2P镜像分发Dragonfly使用
- Pwned Vulnhub
- Windows 桌面应用开发入门
- 手机中的传感器之光线传感器(Android实现)
- 新浪微博PC客户端(DotNet WinForm版)—— 初探
- 478-82(56、128、718、129)
- Office 365禁用所有宏,且不通知
- C# Unicode 转换
- 权限管理中的RBAC与ABAC
- ubuntu系统出错且无法恢复请联系管理员(A problem has occurred and the system can‘t recover,please contact the admini)
- 勇者斗恶龙UVa 11292
- 数据挖掘-关联规则挖掘之Apriori算法