1.SQL ( Structure query language ) 结构化查询语言
1、DDL语句 数据库定义语言: 数据库、表、视图、索引、存储过程,例如CREATE DROP ALTER
2、DCL语句 数据库控制语言: 例如控制用户的访问权限GRANT、REVOKE
3、DML语句 数据库操纵语言: 插入数据INSERT、删除数据DELETE、更新数据UPDATE
4、DQL语句 数据库操纵语言:查询数据SELECT
1.2 基本特征
mysql数据库管理软件,记录事物一些数据特征: 由库,表,记录组成. 库相当于一个文件夹 表相当于一个文件 记录就是文件里面一条一条的内容 表中的成员属性就是一个一个字段 可以为每个项目建立一个数据库 关系型数据库:表与表之间有联系 比如:mysql,oracle,db2,sqlserver 非关系型数据库: key-value 键值对形式 没有表的概念 比如:redis,mongodb,memcache
1.3 表的基本操作
操作文件夹(库) 增 create database db1 charset utf8; # 以utf-8的方式建立一个名为db1的数据库 查 show create database db1; # 查看刚刚建立的那个数据库 show databases; # 显示所有的数据库 改 alter database db1 charset gbk; # 改数据库的字符编码 删 drop database db1; 操作文件(表) 切换文件夹:use db1; 查看当前所在文件夹:select database(); 增 create table t1(id int,name char); # 创建一张表,里面字段id为int,名字为字符类型
# 在表中增加某一个字段
create table t1 add sex enum("man","woman")
查 show create table t1; # 根据表名查看表结构 show tables; # 查看所有的表 desc t1; 查看表的另一种方式 改 alter table t1 modify name char(6); # 改name char的宽度,modify为修改 alter table t1 change name NAME char(7); # 修改name的字段名,name>NAME
# 更改表的名字
alter table t1 rename t99;
删 drop table t1; 操作文件内容(记录) 增 # 添加一个 insert t1(id,name) values(1,'longer1'),(2,'longer2'),(3,'longer3');
# 添加多个
insert t1(id,name) values(1,"ergou")
# 可以不指定字段 但是值必须一一对应
insert into t1 values(3,"yunlong");
# 可以具体指定某个字段的值
insert into t1(id) values(6);
查 select id,name from db1.t1; # 查看数据库db1中t1表中对应的id和name的值(有相对和绝对路径) select * from db1.t1; # 查看查看数据库db1中t1表中所有的字段对应的值
# 查询部分字段的内容
select name from db1.t1/t1;
改 update db1.t1 set name='ergou'; # 全部修改 update db1.t1 set name='longer' where id=2; # 指定修改 删 delete from t1; # 将表的所有记录都删除 delete from t1 where id=2; # 指定删除记录
# 清空数据
delete from t2
truncate table t2 都是清空数据但是 # delete把id号保留,truncate 把id号都清除了
1.4 库操作
1.4.1 系统数据库
nformation_schema: 虚拟库,不占用磁盘空间,存储的是数据库启动后的一些参数,如用户表信息、列信息、权限信息、字符信息等
performance_schema: MySQL 5.5开始新增一个数据库:主要用于收集数据库服务器性能参数,记录处理查询请求时发生的各种事件、锁等现象
mysql: 授权库,主要存储系统用户的权限信息
test: MySQL数据库系统自动创建的测试数据库
(1)语法(help create database)
CREATE DATABASE 数据库名 charset utf8;
# create database ...
# 如果在配置文件中指定了编码格式的话 创建的时候可以不使用 charset utf-8
(2)数据库命名规则:(和python一样)
可以由字母、数字、下划线、@、#、$
区分大小写
唯一性
不能使用关键字如 create select
不能单独使用数字
最长128位
(3)数据库相关操作
查看数据库
show databases;
show create database db1;
select database();
选择数据库
USE 数据库名
删除数据库
DROP DATABASE 数据库名;
修改数据库
alter database db1 charset utf8;
1.5 表操作
1.5.1 什么是存储引擎?
mysql中建立的库===>文件夹
库中建立的表===>文件
现实生活中我们用来存储数据的文件有不同的类型,每种文件类型对应各自不同的处理机制:比如处理文本用txt类型,处理表格用excel,处理图片用png等
数据库中的表也应该有不同的类型,表的类型不同,会对应mysql不同的存取机制,表类型又称为存储引擎。
存储引擎说白了就是如何存储数据、如何为存储的数据建立索引和如何更新、查询数据等技术的实现方
法。因为在关系数据库中数据的存储是以表的形式存储的,所以存储引擎也可以称为表类型(即存储和
操作此表的类型)
在Oracle 和SQL Server等数据库中只有一种存储引擎,所有数据存储管理机制都是一样的。而MySql
数据库提供了多种存储引擎。用户可以根据不同的需求为数据表选择不同的存储引擎,用户也可以根据
自己的需要编写自己的存储引擎
②mysql支持的存储引擎
# InnoDB 存储引擎(mysql默认存储引擎)
2、MyISAM 存储引擎 不支持事务、表锁设计、支持全文索引,主要面向一些 OLAP 数 据库应用,在 MySQL 5.5.8 版本之前是默认的存储引擎(除 Windows 版本外)。数据库系统 与文件系统一个很大的不同在于对事务的支持,MyISAM 存储引擎是不支持事务的。究其根 本,这也并不难理解。用户在所有的应用中是否都需要事务呢?在数据仓库中,如果没有 ETL 这些操作,只是简单地通过报表查询还需要事务的支持吗?此外,MyISAM 存储引擎的 另一个与众不同的地方是,它的缓冲池只缓存(cache)索引文件,而不缓存数据文件,这与 大多数的数据库都不相同。 3、NDB 存储引擎 年,MySQL AB 公司从 Sony Ericsson 公司收购了 NDB 存储引擎。 NDB 存储引擎是一个集群存储引擎,类似于 Oracle 的 RAC 集群,不过与 Oracle RAC 的 share everything 结构不同的是,其结构是 share nothing 的集群架构,因此能提供更高级别的 高可用性。NDB 存储引擎的特点是数据全部放在内存中(从 5.1 版本开始,可以将非索引数 据放在磁盘上),因此主键查找(primary key lookups)的速度极快,并且能够在线添加 NDB 数据存储节点(data node)以便线性地提高数据库性能。由此可见,NDB 存储引擎是高可用、 高性能、高可扩展性的数据库集群系统,其面向的也是 OLTP 的数据库应用类型。 4、Memory 存储引擎 正如其名,Memory 存储引擎中的数据都存放在内存中,数据库重 启或发生崩溃,表中的数据都将消失。它非常适合于存储 OLTP 数据库应用中临时数据的临时表,也可以作为 OLAP 数据库应用中数据仓库的维度表。Memory 存储引擎默认使用哈希 索引,而不是通常熟悉的 B+ 树索引。 5、Infobright 存储引擎 第三方的存储引擎。其特点是存储是按照列而非行的,因此非常 适合 OLAP 的数据库应用。其官方网站是 http://www.infobright.org/,上面有不少成功的数据 仓库案例可供分析。 6、NTSE 存储引擎 网易公司开发的面向其内部使用的存储引擎。目前的版本不支持事务, 但提供压缩、行级缓存等特性,不久的将来会实现面向内存的事务支持。 7、BLACKHOLE 黑洞存储引擎,可以应用于主备复制中的分发主库。 MySQL 数据库还有很多其他存储引擎,上述只是列举了最为常用的一些引擎。如果 你喜欢,完全可以编写专属于自己的引擎,这就是开源赋予我们的能力,也是开源的魅 力所在。
1.5.2 常用的存储引擎
InnoDB : 5.6之后默认的存储引擎 特点: 支持事务,行级锁,外键 MyISAM : 5.6之前默认的存储引擎 特点: 表级锁 MEMORY : 用内存来存储数据(缓存) [目前更多使用的是redis数据库来取代] 特点: 速度快,不能进行持久化存储 BLACKHOLE:黑洞 ,用作同步数据的一种引擎方式[主从数据库集群] 特点: 所有数据不会写入,但是会提示成功.
# 使用存储引擎就行创建数据库
create table innodb1(id int , name char(4)) engine=innodb; show create table innodb1; innodb1.frm 表结构 innodb1.ibd 表数据 create table myisam1(id int ,name char(4)) engine=myisam; myisam1.frm 表结构 myisam1.MYD 表数据 myisam1.MYI 表索引 从上到下,从左到右依次查询,如果设置该字段是索引,会单独拿出来一个文件进行存储查询,速度更快. create table memory1(id int ,name char(4)) engine=memory; memory1.frm 表结构 create table blackhole1(id int ,name char(4)) engine=blackhole; blackhole1.frm 表结构 insert into blackhole1 values(1,"s");
1.5.3 表的增删改查
# 创建表
create table 表名( 字段名1 类型[(宽度) 约束条件], 字段名2 类型[(宽度) 约束条件], 字段名3 类型[(宽度) 约束条件] ); #注意: 1. 在同一张表中,字段名是不能相同 2. 宽度和约束条件可选,中括号内的可有可无 3. 字段名和类型是必须的
(1)创建表
# 下面是创建表t1 查询表 ,再下面是查询表中的内容
mysql> create database db1 charset utf8; Query OK, 1 row affected (0.01 sec) mysql> use db1; Database changed
#### 创建表t1 mysql> create table t1( -> id int, -> name varchar(50), -> sex enum('male','female'), -> age int(3) -> ); Query OK, 0 rows affected (0.01 sec) mysql> show tables; +---------------+ | Tables_in_db1 | +---------------+ | t1 | +---------------+ 1 row in set (0.00 sec) mysql> desc t1; +-------+-----------------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +-------+-----------------------+------+-----+---------+-------+ | id | int(11) | YES | | NULL | | | name | varchar(50) | YES | | NULL | | | sex | enum('male','female') | YES | | NULL | | | age | int(3) | YES | | NULL | | +-------+-----------------------+------+-----+---------+-------+ 4 rows in set (0.06 sec) mysql> select id,name,sex,age from t1; # 查询创建的1表中的id,name,sex,age字段的内容 Empty set (0.00 sec) mysql> select * from t1; # 查询所有字段的内容和上面的等价 Empty set (0.00 sec) mysql> select id,name from t1; # 查询指定字段的内容 (Id,name字段) Empty set (0.00 sec)
# 由于都是刚创建的 于是表中是没有内容的
(2)向表中添加数据
mysql> insert into t1 values(1,'ergou','male',18),(2,'longer','female',30); Query OK, 2 rows affected (0.01 sec) Records: 2 Duplicates: 0 Warnings: 0 mysql> select * from t1; +------+--------+--------+------+ | id | name | sex | age | +------+--------+--------+------+ | 1 | ergou | male | 18 | | 2 | longer | female | 30 | +------+--------+--------+------+ 2 rows in set (0.00 sec) mysql> insert into t1(id) values(3),(4); Query OK, 2 rows affected (0.01 sec) Records: 2 Duplicates: 0 Warnings: 0 mysql> select * from t1; +------+--------+--------+------+ | id | name | sex | age | +------+--------+--------+------+ | 1 | ergou | male | 18 | | 2 | longer | female | 30 | | 3 | NULL | NULL | NULL | | 4 | NULL | NULL | NULL | +------+--------+--------+------+ 4 rows in set (0.00 sec)
# 小结: 如果在表中插入数据的时候没有指定该字段的话,必须一一匹配即是定了多少个必须插入多少个。
# 如果指定了插入的字段,只需要插入指定的数据即可
# 插入多个数据 使用,相互隔离即可,插入的数据中没有指定的字段的值为default默认值中的值
#如果出现输错的情况 可以使用\c就行处理。
(3)查询表结构
#查看表详细结构,可加\G
mysql> show tables; +---------------+ | Tables_in_db1 | +---------------+ | t1 | +---------------+ 1 row in set (0.00 sec) mysql> show create table t1; +-------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | Table | Create Table | +-------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | t1 | CREATE TABLE `t1` ( `id` int(11) DEFAULT NULL, `name` varchar(50) DEFAULT NULL, `sex` enum('male','female') DEFAULT NULL, `age` int(3) DEFAULT NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8 | +-------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ 1 row in set (0.00 sec) # 加上\G可以避免显示上的错误
# 查看建表语句 mysql> show create table t1\G; *************************** 1. row *************************** Table: t1 Create Table: CREATE TABLE `t1` ( `id` int(11) DEFAULT NULL, `name` varchar(50) DEFAULT NULL, `sex` enum('male','female') DEFAULT NULL, `age` int(3) DEFAULT NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8 1 row in set (0.00 sec) ERROR: No query specified mysql> desc t1; +-------+-----------------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +-------+-----------------------+------+-----+---------+-------+ | id | int(11) | YES | | NULL | | | name | varchar(50) | YES | | NULL | | | sex | enum('male','female') | YES | | NULL | | | age | int(3) | YES | | NULL | | +-------+-----------------------+------+-----+---------+-------+ 4 rows in set (0.00 sec)
(4)修改表的结构
语法: 1. 修改表名 ALTER TABLE 表名 RENAME 新表名; 2. 增加字段 ALTER TABLE 表名 ADD 字段名 数据类型 [完整性约束条件…], ADD 字段名 数据类型 [完整性约束条件…]; ALTER TABLE 表名 ADD 字段名 数据类型 [完整性约束条件…] FIRST; # first表示放置位置 ALTER TABLE 表名 ADD 字段名 数据类型 [完整性约束条件…] AFTER 字段名; # 将新字段添加到什么字段后面 3. 删除字段 ALTER TABLE 表名 DROP 字段名; 4. 修改字段 ALTER TABLE 表名 MODIFY 字段名 数据类型 [完整性约束条件…]; ALTER TABLE 表名 CHANGE 旧字段名 新字段名 旧数据类型 [完整性约束条件…]; ALTER TABLE 表名 CHANGE 旧字段名 新字段名 新数据类型 [完整性约束条件…];
# 1.在表student10 中添加字段 mysql> desc student10; +-------+---------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +-------+---------+------+-----+---------+-------+ | id | int(11) | YES | | NULL | | +-------+---------+------+-----+---------+-------+ 1 row in set (0.00 sec) mysql> alter table student10 -> add name varchar(20) not null, -> add age int(3) not null default 22; Query OK, 0 rows affected (0.04 sec) Records: 0 Duplicates: 0 Warnings: 0 mysql> desc student10; +-------+-------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +-------+-------------+------+-----+---------+-------+ | id | int(11) | YES | | NULL | | | name | varchar(20) | NO | | NULL | | | age | int(3) | NO | | 22 | | +-------+-------------+------+-----+---------+-------+ 3 rows in set (0.00 sec)
# 2.删除字段sex,本身我也没有加哈哈。 mysql> alter table student10 -> drop sex;
# 3 修改字段类型(1) modify (2)把字段修改了并设置为主键,并且用 auto_increment修饰 键值自动加1如果为null时 mysql> desc student10; +-------+-------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +-------+-------------+------+-----+---------+-------+ | id | int(11) | YES | | NULL | | | name | varchar(20) | NO | | NULL | | | age | int(3) | NO | | 22 | | +-------+-------------+------+-----+---------+-------+ 3 rows in set (0.00 sec) # 修改 age中的type 为int(6) mysql> alter table student10 modify age int(6); Query OK, 0 rows affected (0.05 sec) Records: 0 Duplicates: 0 Warnings: 0 mysql> desc student10; +-------+-------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +-------+-------------+------+-----+---------+-------+ | id | int(11) | YES | | NULL | | | name | varchar(20) | NO | | NULL | | | age | int(6) | YES | | NULL | | +-------+-------------+------+-----+---------+-------+ 3 rows in set (0.00 sec) # 修改id 中的类型 并且将其设置为主键,并且有属性auto_increment mysql> alter table student10 -> modify id int(10) not null primary key auto_increment; Query OK, 0 rows affected (0.05 sec) Records: 0 Duplicates: 0 Warnings: 0 mysql> desc student10; +-------+-------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +-------+-------------+------+-----+---------+----------------+ | id | int(10) | NO | PRI | NULL | auto_increment | | name | varchar(20) | NO | | NULL | | | age | int(6) | YES | | NULL | | +-------+-------------+------+-----+---------+----------------+ 3 rows in set (0.01 sec)
# 4 # auto_increment: 自增加1,[一般是对unique或者 primary key 进行设置] 对主键进行约束 如上面第三个中的第二个修改字段中type属性,并且加上这个特性
# 5 增加主键 mysql> alter table student1 -> modify name varchar(10) not null primary key; 增加主键和自动增长 mysql> alter table student1 -> modify id int not null primary key auto_increment; 删除主键 删除自增约束 mysql> alter table student10 modify id int(11) not null; 删除主键 mysql> alter table student10 -> drop primary key;
(5)删除表
DROP TABLE 表名;
1.6 对表中内容的操作
增 # 添加多个 insert t1(id,name) values(1,'longer1'),(2,'longer2'),(3,'longer3'); # 添加一个 insert t1(id,name) values(1,"ergou") # 可以不指定字段 但是值必须一一对应 insert into t1 values(3,"yunlong"); # 可以具体指定某个字段的值 insert into t1(id) values(6); 查 select id,name from db1.t1; # 查看数据库db1中t1表中对应的id和name的值(有相对和绝对路径) select * from db1.t1; # 查看查看数据库db1中t1表中所有的字段对应的值 # 查询部分字段的内容 select name from db1.t1/t1; 改 update db1.t1 set name='ergou'; # 全部修改 update db1.t1 set name='longer' where id=2; # 指定修改 删 delete from t1; # 将表的所有记录都删除 delete from t1 where id=2; # 指定删除记录 # 清空数据 delete from t2 truncate table t2 都是清空数据但是 # delete把id号保留,truncate 把id号都清除了
2.数据类型
1.数值类型(整型、浮点型)
整数类型:TINYINT SMALLINT MEDIUMINT INT BIGINT(代表的整数范围不一样)
其中常用的是tinyint
作用:存储年龄,等级,id,各种号码等
注意点:整型无需指定宽度,使用默认的就好了(因为整型不指定存储宽度,只指定显示宽度,而显示宽度又默认指定好了,所以无需指定宽度)其它数值类型指的是存储宽度。
======================================== tinyint[(m)] [unsigned] [zerofill] 小整数,数据类型用于保存一些范围的整数数值范围: 有符号: -128 ~ 127 无符号: 0 ~ 255 PS: MySQL中无布尔值,使用tinyint(1)构造。 ======================================== int[(m)][unsigned][zerofill] 整数,数据类型用于保存一些范围的整数数值范围: 有符号: -2147483648 ~ 2147483647 无符号: 0 ~ 4294967295(42亿) ======================================== bigint[(m)][unsigned][zerofill] 大整数,数据类型用于保存一些范围的整数数值范围: 有符号: -9223372036854775808 ~ 9223372036854775807 无符号: 0 ~ 18446744073709551615
注意:zerofill : 零填充,位数不够的时候用前导0
#(1)tinyint 存值范围
默认是有符号的。
-128 ~ 127 # 有符号
分别存入 -129 -128 127 128得出结果:
mysql> create table t2(x tinyint);
mysql> insert into t2 values(-128); Query OK, 1 row affected (0.01 sec) mysql> insert into t2 values(-129); ERROR 1264 (22003): Out of range value for column 'x' at row 1 mysql> insert into t2 values(127); Query OK, 1 row affected (0.00 sec) mysql> insert into t2 values(128); ERROR 1264 (22003): Out of range value for column 'x' at row 1
0-255 无符号
分别存入 -1 0 255 256 得出结果。
mysql> create table t2(x tinyint); Query OK, 0 rows affected (0.02 sec) mysql> desc t2; +-------+------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +-------+------------+------+-----+---------+-------+ | x | tinyint(4) | YES | | NULL | | +-------+------------+------+-----+---------+-------+ 1 row in set (0.01 sec) mysql> drop table t2; Query OK, 0 rows affected (0.01 sec) mysql> create table t2(x tinyint unsigned); Query OK, 0 rows affected (0.01 sec) mysql> insert into t2 values(-1); ERROR 1264 (22003): Out of range value for column 'x' at row 1 mysql> insert into t2 values(0); Query OK, 1 row affected (0.01 sec) mysql> insert into t2 values(255); Query OK, 1 row affected (0.01 sec) mysql> insert into t2 values(256); ERROR 1264 (22003): Out of range value for column 'x' at row 1
# (2)int (有符号和无符号)
============有符号nt============= #int默认为有符号
create table t3(x int); #默认为有符号整数
-2147483648 ~ 2147483647
无符号的
create table t4(x int unsigned);
# (3)
mysql> create table t7(x int(3) zerofill); Query OK, 0 rows affected (0.01 sec) mysql> insert into t7 values(1),(11),(111); Query OK, 3 rows affected (0.00 sec) Records: 3 Duplicates: 0 Warnings: 0 mysql> insert into t7 values(1111); Query OK, 1 row affected (0.00 sec) mysql> select * from t7; +------+ | x | +------+ | 001 | | 011 | | 111 | | 1111 | # 超出宽度限制仍然可以存 +------+ 4 rows in set (0.01 sec)
小结:不同的整数,只是表达范围不一样而已。
2.浮点型
定点数类型 DEC等同于DECIMAL
浮点类型:FLOAT DOUBLE
作用:存储薪资、身高、体重、体质参数等
语法:
#FLOAT[(M,D)] [UNSIGNED] [ZEROFILL] # 这里M和D代表指定的宽度,M代表最多整数部分有多少,D代表小数部分最多有多少 定义: 单精度浮点数(非准确小数值),m是数字总个数,d是小数点后个数。m最大值为255,d最大值为30 有符号: -3.402823466E+38 to -1.175494351E-38, 1.175494351E-38 to 3.402823466E+38 无符号: 1.175494351E-38 to 3.402823466E+38 精确度: **** 随着小数的增多,精度变得不准确 **** ====================================== #DOUBLE[(M,D)] [UNSIGNED] [ZEROFILL] 定义: 双精度浮点数(非准确小数值),m是数字总个数,d是小数点后个数。m最大值为255,d最大值为30 有符号: -1.7976931348623157E+308 to -2.2250738585072014E-308 2.2250738585072014E-308 to 1.7976931348623157E+308 无符号: 2.2250738585072014E-308 to 1.7976931348623157E+308 精确度: ****随着小数的增多,精度比float要高,但也会变得不准确 **** ====================================== decimal[(m[,d])] [unsigned] [zerofill] 定义: 准确的小数值,m是数字总个数(负号不算),d是小数点后个数。 m最大值为65,d最大值为30。 精确度: **** 随着小数的增多,精度始终准确 **** 对于精确数值计算时需要用此类型 decaimal能够存储精确值的原因在于其内部按照字符串存储。
mysql> create table t1(x float(255,30)); #建表成功 Query OK, 0 rows affected (0.02 sec) mysql> create table t2(x double(255,30)); #建表成功 Query OK, 0 rows affected (0.02 sec)
mysql> create table t3(x decimal(65,30)); #建表成功 Query OK, 0 rows affected (0.02 sec)
mysql> insert into t1 values(1.1111111111111111111111111111111); #小数点后31个1 Query OK, 1 row affected (0.01 sec) mysql> insert into t2 values(1.1111111111111111111111111111111); Query OK, 1 row affected (0.00 sec) mysql> insert into t3 values(1.1111111111111111111111111111111); Query OK, 1 row affected, 1 warning (0.01 sec) mysql> select * from t1; #随着小数的增多,精度开始不准确 +----------------------------------+ | x | +----------------------------------+ | 1.111111164093017600000000000000 | +----------------------------------+ row in set (0.00 sec) mysql> select * from t2; #精度比float要准确点,但随着小数的增多,同样变得不准确 +----------------------------------+ | x | +----------------------------------+ | 1.111111111111111200000000000000 | +----------------------------------+ row in set (0.00 sec)
mysql> select * from t3; #精度始终准确,d为30,于是只留了30位小数 +----------------------------------+ | x | +----------------------------------+ | 1.111111111111111111111111111111 | +----------------------------------+ row in set (0.00 sec)
注意:
mysql> create table t3(f1 float, f2 double, f3 decimal);
mysql> insert into t3 values(1.222222222222222222,1.2222222222222222,1.222222) -> ; Query OK, 1 row affected, 1 warning (0.00 sec) mysql> select * from t3; +---------+-------------------+------+ | f1 | f2 | f3 | +---------+-------------------+------+ | 1.22222 | 1.222222222222222 | 1 | +---------+-------------------+------+ 1 row in set (0.00 sec)
默认: float 的小数位数较少 double的默认小数的位数较多,decimal的默认小数位数为0,都是要自己设置的。
3.日期类型
DATE TIME DATETIME TIMESTAMP YEAR
作用:存储用户注册时间,文章发布时间,员工入职时间,出生时间,过期时间等
YEAR
YYYY(
1901
/
2155
)
DATE
YYYY
-
MM
-
DD(
1000
-
01
-
01
/
9999
-
12
-
31
)
TIME
HH:MM:SS(
'-838:59:59'
/
'838:59:59'
)
DATETIME
YYYY
-
MM
-
DD HH:MM:SS(
1000
-
01
-
01
00
:
00
:
00
/
9999
-
12
-
31
23
:
59
:
59
Y)
TIMESTAMP
YYYYMMDD HHMMSS(
1970
-
01
-
01
00
:
00
:
00
/
2037
年某时)
date YYYY-MM-DD 年月日 (出生日期)
time HH:MM:SS 时分秒 (竞赛时间)
year YYYY 年分值 (红酒82年拉菲 82年矿泉水)
datetime YYYY-MM-DD HH:MM:SS 年月日时分秒 (登录时间,下单时间)
============year===========
# 范围是1900 ~ 2155
mysql> create table t10(born_year year);
Query OK, 0 rows affected (0.01 sec)
mysql> insert into t10 values (1900);
ERROR 1264 (22003): Out of range value for column 'born_year' at row 1
mysql> insert into t10 values(1901);
Query OK, 1 row affected (0.01 sec)
mysql> insert into t10 values(2155);
Query OK, 1 row affected (0.00 sec)
mysql> insert into t10 values(2156);
ERROR 1264 (22003): Out of range value for column 'born_year' at row
=
=
=
=
=
=
=
=
=
=
=
=
date,time,datetime
=
=
=
=
=
=
=
=
=
=
=
mysql> create table t4(d date, t time, y year, dt datetime); Query OK, 0 rows affected (0.02 sec) mysql> insert into t4 values(now(),now(),now(),now()); Query OK, 1 row affected, 1 warning (0.01 sec) mysql> insert into t4 values("2020-1-1","23:23:23","2038","2099-1-1 23:23:23")); Query OK, 1 row affected (0.00 sec) mysql> select * from t4; +------------+----------+------+---------------------+ | d | t | y | dt | +------------+----------+------+---------------------+ | 2019-06-17 | 09:54:02 | 2019 | 2019-06-17 09:54:02 | | 2020-01-01 | 23:23:23 | 2038 | 2099-01-01 23:23:23 | +------------+----------+------+---------------------+ 2 rows in set (0.00 sec) mysql> desc t4; +-------+----------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +-------+----------+------+-----+---------+-------+ | d | date | YES | | NULL | | | t | time | YES | | NULL | | | y | year(4) | YES | | NULL | | | dt | datetime | YES | | NULL | | +-------+----------+------+-----+---------+-------+ 4 rows in set (0.00 sec)
# timestamp YYYYMMDDHHMMSS 自动更新时间戳,不需要你手动写入(修改表的时候,自动更新,到时候可以看到最后一次表更新时间;)
create table t6(dt datetime,ts timestamp);
insert into t6 values(null,null);
insert into t6 values(20190103121212,20190103121212);
insert into t6 values(20190103121212,20380118121212);
mysql> create table t6(dt datetime, ts timestamp); Query OK, 0 rows affected (0.04 sec) mysql> insert into t6 values(null,null); Query OK, 1 row affected (0.00 sec) mysql> select * from t6; +------+---------------------+ | dt | ts | +------+---------------------+ | NULL | 2019-06-17 09:58:34 | +------+---------------------+ 1 row in set (0.00 sec) mysql> insert into t6 values(20190103121212,20190103121212); Query OK, 1 row affected (0.00 sec) mysql> insert into t6 values(20190103121212,20380118121212); Query OK, 1 row affected (0.00 sec) mysql> select * from t6; +---------------------+---------------------+ | dt | ts | +---------------------+---------------------+ | NULL | 2019-06-17 09:58:34 | | 2019-01-03 12:12:12 | 2019-01-03 12:12:12 | | 2019-01-03 12:12:12 | 2038-01-18 12:12:12 | +---------------------+---------------------+ 3 rows in set (0.00 sec)
=
=
=
=
=
=
=
=
=
=
=
=
注意啦,注意啦,注意啦
=
=
=
=
=
=
=
=
=
=
=
1.
单独插入时间时,需要以字符串的形式,按照对应的格式插入
2.
插入年份时,尽量使用
4
位值
3.
插入两位年份时,<
=
69
,以
20
开头,比如
50
, 结果
2050
>
=
70
,以
19
开头,比如
71
,结果
1971
mysql> create table t7(y year); ERROR 1050 (42S01): Table 't7' already exists mysql> drop table t7; Query OK, 0 rows affected (0.08 sec) mysql> create table t7(y year); Query OK, 0 rows affected (0.02 sec) mysql> insert into t7 values(50),(70); Query OK, 2 rows affected (0.01 sec) Records: 2 Duplicates: 0 Warnings: 0 mysql> select * from t7; +------+ | y | +------+ | 2050 | | 1970 | +------+ 2 rows in set (0.00 sec)
mysql> create table student( -> id int, -> name varchar(20), -> born_year year, -> birth date, -> class_time time, -> reg_time datetime); Query OK, 0 rows affected (0.01 sec) mysql> desc student; +------------+-------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +------------+-------------+------+-----+---------+-------+ | id | int(11) | YES | | NULL | | | name | varchar(20) | YES | | NULL | | | born_year | year(4) | YES | | NULL | | | birth | date | YES | | NULL | | | class_time | time | YES | | NULL | | | reg_time | datetime | YES | | NULL | | +------------+-------------+------+-----+---------+-------+ 6 rows in set (0.00 sec) mysql> insert into student values -> (1,"hanhan","1960","1960-02-12","12:12:12","2019-06-15 12:12:12"), -> (2,"longer","1999","1999-12-12","12:12:12","2019-06-15 12:12:12"), -> (3,"ergou","2000","2000-09-12","12:12:12","2019-06-15 12:12:12"); Query OK, 3 rows affected (0.01 sec) Records: 3 Duplicates: 0 Warnings: 0 mysql> select * from student; +------+--------+-----------+------------+------------+---------------------+ | id | name | born_year | birth | class_time | reg_time | +------+--------+-----------+------------+------------+---------------------+ | 1 | hanhan | 1960 | 1960-02-12 | 12:12:12 | 2019-06-15 12:12:12 | | 2 | longer | 1999 | 1999-12-12 | 12:12:12 | 2019-06-15 12:12:12 | | 3 | ergou | 2000 | 2000-09-12 | 12:12:12 | 2019-06-15 12:12:12 | +------+--------+-----------+------------+------------+---------------------+ 3 rows in set (0.00 sec)
datetime与timestamp的区别
在实际应用的很多场景中,MySQL的这两种日期类型都能够满足我们的需要,存储精度都为秒,但在某些情况下,会展现出他们各自的优劣。 下面就来总结一下两种日期类型的区别。 1.DATETIME的日期范围是1001——9999年,TIMESTAMP的时间范围是1970——2038年。 2.DATETIME存储时间与时区无关,TIMESTAMP存储时间与时区有关,显示的值也依赖于时区。在mysql服务器, 操作系统以及客户端连接都有时区的设置。 3.DATETIME使用8字节的存储空间,TIMESTAMP的存储空间为4字节。因此,TIMESTAMP比DATETIME的空间利用率更高。 4.DATETIME的默认值为null;TIMESTAMP的字段默认不为空(not null),默认值为当前时间(CURRENT_TIMESTAMP), 如果不做特殊处理,并且update语句中没有指定该列的更新值,则默认更新为当前时间。
4.字符类型
(1)
注意:char和varchar括号内的参数指的都是字符的长度(个数) char类型:定长,简单粗暴,浪费空间,存取速度快 字符长度范围:0-255(一个中文是一个字符,是utf8编码的3个字节) 存储: 存储char类型的值时,会往右填充空格来满足长度 例如:指定长度为10,存>10个字符则报错,存<10个字符则用空格填充直到凑够10个字符存储 检索: 在检索或者说查询时,查出的结果会自动删除尾部的空格,除非我们打开pad_char_to_full_length SQL模式(SET sql_mode = 'PAD_CHAR_TO_FULL_LENGTH'; # 设置MySQL的参数,使得取出完整的长度)。 就比如存的帅哥加上后面三个字符,一共五个字符,存的时候是五个字符,会给你补全空格,取的时候只会取出帅哥,查出的结果会自动删除尾部的空格,得到的就只有两个字符了。 varchar类型:变长,精准,节省空间,存取速度慢 字符长度范围:0-65535(如果大于21845会提示用其他类型 。mysql行最大限制为65535字节,字符编码为utf-8:https://dev.mysql.com/doc/refman/5.7/en/column-count-limit.html) 存储: varchar类型存储数据的真实内容,不会用空格填充,如果'ab ',尾部的空格也会被存起来 强调:varchar类型会在真实数据前加1-2Bytes的前缀,(由于varchar的变长,造成实际上不知道多少字符才构成一个字段,因此需要该前缀来反映数据的真实性)该前缀用来表示真实数据的bytes字节数
(1-2Bytes最大表示65535个数字,正好符合mysql对row的最大字节限制,即已经足够使用) 如果真实的数据<255bytes则需要1Bytes的前缀(1Bytes=8bit 2**8最大表示的数字为255) 如果真实的数据>255bytes则需要2Bytes的前缀(2Bytes=16bit 2**16最大表示的数字为65535) 检索: 尾部有空格会保存下来,在检索或者说查询时,也会正常显示包含空格在内的内容 总结: 对于MySQL来说,无论是char还是varchar,在取的时候时候只会按照值进行比较,不会管默认有多少空格,因此取出的时候尾部空格就自动删除了。因此,所查字段尾部有空格,MySQL还是会忽略该空格,对查询结果无影响。
但是对于其他地方的空格,MySQL不相同具备此功能。like查询会保留空格查询。 因为varchar需要存一个前缀,所以后面存的时候就会多出 1-2 bytes 来表示字符数
# char填充空格来满足固定长度,但是在查询时却会很不要脸地删除尾部的空格(装作自己好像没有浪费过空间一样),然后修改sql_mode让其现出原形
mysql> create table t1(x char(5),y varchar(5)); ERROR 1050 (42S01): Table 't1' already exists mysql> drop table t1; Query OK, 0 rows affected (0.00 sec) mysql> create table t1(x char(5),y varchar(5)); Query OK, 0 rows affected (0.02 sec) mysql> insert into t1 values("龙儿","臭猪儿 "); -> \c mysql> insert into t1 values("龙儿","臭猪儿 "); Query OK, 1 row affected (0.00 sec) mysql> SET sql_mode=""; Query OK, 0 rows affected, 1 warning (0.00 sec) #在检索时char很不要脸地将自己浪费的2个字符给删掉了,装的好像自己没浪费过空间一样,varchar 在检索查询的时候会保留 mysql> select x,char_length(x),y,char_length(y) from t1; +--------+----------------+-----------+----------------+ | x | char_length(x) | y | char_length(y) | +--------+----------------+-----------+----------------+ | 龙儿 | 2 | 臭猪儿 | 4 | +--------+----------------+-----------+----------------+ 1 row in set (0.00 sec) #略施小计,让char现出原形 mysql> SET sql_mode = 'PAD_CHAR_TO_FULL_LENGTH'; Query OK, 0 rows affected (0.00 sec) #这下子char原形毕露了...... mysql> select x,char_length(x),y,char_length(y) from t1; +-----------+----------------+-----------+----------------+ | x | char_length(x) | y | char_length(y) | +-----------+----------------+-----------+----------------+ | 龙儿 | 5 | 臭猪儿 | 4 | +-----------+----------------+-----------+----------------+ 1 row in set (0.00 sec)
char类型:2个中文字符+3个空格=9Bytes
#varchar类型:3个中文字符+1个空格=10Bytes
mysql> select x,length(x),length(y) from t1; +-----------+-----------+-----------+ | x | length(x) | length(y) | +-----------+-----------+-----------+ | 龙儿 | 9 | 10 | +-----------+-----------+-----------+ 1 row in set (0.00 sec)
#常用字符串系列:char与varchar
注:虽然varchar使用起来较为灵活,但是从整个系统的性能角度来说,char数据类型的处理速度更快,有时甚至可以超出varchar
处理速度的
50
%
。
因此,用户在设计数据库时应当综合考虑各方面的因素,以求达到最佳的平衡。
text:text数据类型用于保存变长的大字符串,可以组多到
65535
(
2
*
*
16
−
1
)个字符。
5.枚举类型与集合类型
字段的值只能在给定范围中选择,如单选框,多选框
enum 单选 只能在给定的范围内选一个值,如性别 sex 男male/女female
set 多选 在给定的范围内可以选择一个或一个以上的值(爱好1,爱好2,爱好3...)
mysql> create table t1( -> name varchar(50), -> sex enum('male','female'), -> level enum('vip1','vip2','vip3'), -> hobby set('play','music','read','study') -> ); Query OK, 0 rows affected (0.02 sec) mysql> insert into t1 values ('ergou','male','vip3','music,read,study'), ('lonnger','female','vip1','study'); Query OK, 2 rows affected (0.01 sec) Records: 2 Duplicates: 0 Warnings: 0 mysql> select * from t1; +--------+--------+-------+------------------+ | name | sex | level | hobby | +--------+--------+-------+------------------+ | ergou | male | vip3 | music,read,study | | longer | female | vip1 | study | +--------+--------+-------+------------------+ 2 rows in set (0.00 sec)
6.完整性约束
①介绍
约束条件与数据类型的宽度一样,都是可选参数
作用:用于保证数据的完整性和一致性
主要分为:
PRIMARY KEY (PK) 标识该字段为该表的主键,可以唯一的标识记录
FOREIGN KEY (FK) 标识该字段为该表的外键
NOT NULL 标识该字段不能为空
UNIQUE KEY (UK) 标识该字段的值是唯一的
AUTO_INCREMENT 标识该字段的值自动增长(整数类型,而且为主键)
DEFAULT 为该字段设置默认值
UNSIGNED 无符号
ZEROFILL 使用0填充
说明:。
1.
是否允许为空,默认NULL,可设置NOT NULL,字段不允许为空,必须赋值
2.
字段是否有默认值,缺省的默认值是NULL,如果插入记录时不给字段赋值,此字段使用默认值
sex enum(
'male'
,
'female'
)
not
null default
'male'
age
int
unsigned NOT NULL default
20
必须为正值(无符号) 不允许为空 默认是
20
3.
是否是key
主键 primary key
外键 foreign key
索引 (index,unique...)
②not null与default
是否可空,null表示空,非字符串 not null - 不可空 null - 可空 默认值,创建列时可以指定默认值,当插入数据时如果未主动设置,则自动添加默认值 create table t1( id int, name char(6), sex enum('male','female') not null default 'male' # 这里则是设置了性别不为空,为空时则设置默认值为male );
==================not null==================== mysql> create table t1(id int); # id字段默认可以插入空 mysql> desc t1; +-------+---------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +-------+---------+------+-----+---------+-------+ | id | int(11) | YES | | NULL | | +-------+---------+------+-----+---------+-------+ mysql> insert into t1 values(); #可以插入空 mysql> create table t2(id int not null); #设置字段id不为空 mysql> desc t2; +-------+---------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +-------+---------+------+-----+---------+-------+ | id | int(11) | NO | | NULL | | +-------+---------+------+-----+---------+-------+ mysql> insert into t2 values(); #不能插入空 ERROR 1364 (HY000): Field 'id' doesn't have a default value ==================default==================== #设置id字段有默认值后,则无论id字段是null还是not null,都可以插入空,插入空默认填入default指定的默认值 mysql> create table t3(id int default 1); mysql> alter table t3 modify id int not null default 1;
## 可以写成一行代码:
create table t3(id int not null default 1);
# 例子
mysql> create table student( -> name varchar(20) not null, -> age int(3) unsigned not null default 18, -> sex enum('male','female') default 'male', -> hobby set('paly','eat','read','music') default 'paly,eat' -> ); ysql> desc student; +-------+----------------------------------+------+-----+----------+-------+ | Field | Type | Null | Key | Default | Extra | +-------+----------------------------------+------+-----+----------+-------+ | name | varchar(20) | NO | | NULL | | | age | int(3) unsigned | NO | | 18 | | | sex | enum('male','female') | YES | | male | | | hobby | set('paly','eat','read','music') | YES | | paly,eat | | +-------+----------------------------------+------+-----+----------+-------+ 4 rows in set (0.01 sec) mysql> insert into student(name) values('ergou'); Query OK, 1 row affected (0.00 sec) mysql> select * from student; +-------+-----+------+----------+ | name | age | sex | hobby | +-------+-----+------+----------+ | ergou | 18 | male | paly,eat | +-------+-----+------+----------+ 1 row in set (0.00 sec)
③unique(唯一)
作用:为表中只能添加一种字符,且不能重复。例如可以在ID或者name下面添加unique,使得添加的字符唯一。
单列唯一
设置某一项内只能设置唯一一个字段,不能重复设置。
# 方式1创建
ysql> create table department1( -> id int, -> name varchar(20) unique, -> comment varchar(100) -> ); Query OK, 0 rows affected (0.01 sec) mysql> create table department2( -> id int, -> name char(10), -> unique(id), -> unique(name) -> ); Query OK, 0 rows affected (0.03 sec) # 方式2 创建 mysql> desc department2; +-------+----------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +-------+----------+------+-----+---------+-------+ | id | int(11) | YES | UNI | NULL | | | name | char(10) | YES | UNI | NULL | | +-------+----------+------+-----+---------+-------+ 2 rows in set (0.00 sec) # 值的唯一性 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'
not null+unique的化学反应
就相对于后面要介绍的
primary key: 主键,唯一不为空的值.可以唯一表达每条记录[辨别数据唯一性的一个身份证]
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)
联合唯一
设置只要几项加起来不是相同即可,但是同时也可设置单列唯一。
# (1)联合唯一主键:非空+联合唯一的约束 => 显示 PRI create table t1_server(id int,server_name char(10) not null ,ip char(15) not null,port int not null,unique(ip,port)) insert into t1_server(id,server_name,ip,port) values(4,'aa',"192.168.16.3",3306); insert into t1_server(id,server_name,ip,port) values(4,'aa',"192.168.16.3",3307); insert into t1_server(id,server_name,ip,port) values(4,'aa',"192.168.16.3",3306); mysql> desc t1_server; +-------------+----------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +-------------+----------+------+-----+---------+-------+ | id | int(11) | YES | | NULL | | | server_name | char(10) | NO | | NULL | | | ip | char(15) | NO | PRI | NULL | | | port | int(11) | NO | PRI | NULL | | +-------------+----------+------+-----+---------+-------+ 4 rows in set (0.00 sec) # (2)显示索引 : 可空+联合唯一约束 => 显示MUL 普通索引 mysql> create table t2_server(id int,server_name char(10) not null,ip char(15), port int ,unique(ip,port)) -> ; Query OK, 0 rows affected (0.02 sec) mysql> insert into t2_server(id,server_name,ip,port) values(5,'aa',null,null); Query OK, 1 row affected (0.00 sec) mysql> insert into t2_server(id,server_name,ip,port) values(5,'aa',null,null); Query OK, 1 row affected (0.00 sec) mysql> insert into t2_server values(6,'aa','192.168.16.3',3306); Query OK, 1 row affected (0.00 sec) mysql> insert into t2_server(id,server_name,ip,port) values(7,'aa',"192.168.16.3",3307); Query OK, 1 row affected (0.01 sec) mysql> desc t2_server; +-------------+----------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +-------------+----------+------+-----+---------+-------+ | id | int(11) | YES | | NULL | | | server_name | char(10) | NO | | NULL | | | ip | char(15) | YES | MUL | NULL | | | port | int(11) | YES | | NULL | | +-------------+----------+------+-----+---------+-------+ 4 rows in set (0.01 sec) (3) 如果1中类型(主键和联合主键)都在一个表当中出现,如何显示? mysql> create table t1_server(id int,server_name char(10) not null ,ip char(15) not null,port int not null,unique(ip,port)); mysql> alter table t1_server add primary key(id); Query OK, 0 rows affected (0.03 sec) Records: 0 Duplicates: 0 Warnings: 0 mysql> desc t1_server; +-------------+----------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +-------------+----------+------+-----+---------+-------+ | id | int(11) | NO | PRI | NULL | | | server_name | char(10) | NO | | NULL | | | ip | char(15) | NO | MUL | NULL | | | port | int(11) | NO | | NULL | | +-------------+----------+------+-----+---------+-------+ 4 rows in set (0.00 sec)
# 没有在定义表的时候定义的时候可以在外部使用这样的命令就行修改字典的属性
1.添加/删除 not null约束 alter table 表名 modify 别名 类型 2.添加/删除 unique 唯一索引 alter table 表名 add unique(id); alter table 表名 drop index 索引名 3.添加/删除primary key 主键 alter table 表名 add primary key(id) alter table 表名 drop primary key; 4.添加/删除foreign key 外键
④primary key(主键)
primary key字段的值不为空且唯一(not null unique),在默认存储引擎为innodb的表中,一张表内必须有一个主键
一个表中可以:
单列做主键
多列做主键(复合主键)
但一个表内只能有一个主键primary key
通常是id设置为主键
# 方式1利用not null unique
mysql> create table department1( -> id int not null unique, -> name varchar(20) not null unique, -> comment varchar(100) -> ); Query OK, 0 rows affected (0.01 sec) 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 | | +---------+--------------+------+-----+---------+-------+ 3 rows in set (0.01 sec) # 方式2利用primary key mysql> create table department2( -> id int primary key, -> name varchar(20), -> comment varchar(100) -> ); Query OK, 0 rows affected (0.03 sec) 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 | | +---------+--------------+------+-----+---------+-------+ 3 rows in set (0.00 sec) # 方式3在所有字段后单独定义primary key mysql> create table department3( -> id int, -> name varchar(20), -> comment varchar(100), -> constraint pk_name primary key(id); mysql> create table department3( id int, name varchar(20), comment varchar(100), constraint pk_name primary key(id) -> ); Query OK, 0 rows affected (0.01 sec) mysql> desc department3; +---------+--------------+------+-----+---------+-------+ | 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.00 sec)
多列主键:
mysql> create table service( -> ip varchar(15), -> port char(5), -> service_name varchar(10) not null, -> primary key(ip,port) -> ); Query OK, 0 rows affected (0.02 sec) 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 -> ("192.168.22.1","3306","mysql"), -> ('192.168.22.13','3306','mgodb') -> ; Query OK, 2 rows affected (0.00 sec) Records: 2 Duplicates: 0 Warnings: 0 mysql> insert into service values('192.168.22.1','3306','mysql');
#不可以重复 唯一的 ERROR 1062 (23000): Duplicate entry '192.168.22.1-3306' for key 'PRIMARY'
⑤auto_increment(约束条件)
约束字段为自动增长,被约束的字段必须同时被key约束
# 不指定id即是自动增长
mysql> create table student( -> id int primary key auto_increment, -> name varchar(20), -> sex enum('male','female') default 'male' -> ); Query OK, 0 rows affected (0.03 sec) 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 | | +-------+-----------------------+------+-----+---------+----------------+ 3 rows in set (0.00 sec) mysql> insert into student(name) values -> ('longer'), -> ('ergou'); Query OK, 2 rows affected (0.01 sec) Records: 2 Duplicates: 0 Warnings: 0 mysql> select * from student; +----+--------+------+ | id | name | sex | +----+--------+------+ | 1 | longer | male | | 2 | ergou | male | +----+--------+------+ 2 rows in set (0.00 sec)
# 也可以指定id
mysql> insert into student(name) values -> ('longer'), -> ('ergou'); Query OK, 2 rows affected (0.01 sec) Records: 2 Duplicates: 0 Warnings: 0 mysql> select * from student; +----+--------+------+ | id | name | sex | +----+--------+------+ | 1 | longer | male | | 2 | ergou | male | +----+--------+------+ 2 rows in set (0.00 sec) mysql> insert into student values(4,'hanhan',"female"); Query OK, 1 row affected (0.00 sec) mysql> insert into student values(7,"agang",'male'); Query OK, 1 row affected (0.00 sec) mysql> select * from student; +----+--------+--------+ | id | name | sex | +----+--------+--------+ | 1 | longer | male | | 2 | ergou | male | | 4 | hanhan | female | | 7 | agang | male | +----+--------+--------+ 4 rows in set (0.00 sec)
#对于自增的字段,在用delete删除后,再插入值,该字段仍按照删除前的位置继续增长(id号保留)
# truncate清空表,比起delete一条一条地删除记录,truncate是直接清空表,在删除大表时用它,直接把id号(重置)
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("linglong"); Query OK, 1 row affected (0.00 sec) # 1 mysql> select * from student; +----+----------+------+ | id | name | sex | +----+----------+------+ | 8 | linglong | male | +----+----------+------+ 1 row in set (0.00 sec) # 2 mysql> truncate student; Query OK, 0 rows affected (0.01 sec) mysql> insert into student(name) values('ergou'); Query OK, 1 row affected (0.01 sec) mysql> select * from student; +----+-------+------+ | id | name | sex | +----+-------+------+ | 1 | ergou | male | +----+-------+------+ 1 row in set (0.00 sec)
约束条件拓展
#在创建完表后,修改自增字段的起始值
#在创建完表后,修改自增字段的起始值
mysql> create table student( -> id int primary key auto_increment, -> name varchar(20), -> sex enum('male','female') default 'male' -> ); Query OK, 0 rows affected (0.02 sec) mysql> alter table student auto_increment=3; Query OK, 0 rows affected (0.01 sec) Records: 0 Duplicates: 0 Warnings: 0 mysql> show create table student; +---------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | Table | Create Table | +---------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | student | CREATE TABLE `student` ( `id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(20) DEFAULT NULL, `sex` enum('male','female') DEFAULT 'male', PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8 | +---------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ 1 row in set (0.01 sec) mysql> insert into student(name) values('ergou'); Query OK, 1 row affected (0.00 sec) mysql> select * from student; +----+-------+------+ | id | name | sex | +----+-------+------+ | 3 | ergou | male | +----+-------+------+ 1 row in set (0.00 sec) # 运行show create table student 可以发现下一次表的开始的索引已经是4了 mysql> show create table student\G *************************** 1. row *************************** Table: student Create Table: CREATE TABLE `student` ( `id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(20) DEFAULT NULL, `sex` enum('male','female') DEFAULT 'male', PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8 1 row in set (0.00 sec)
#也可以创建表时指定auto_increment的初始值,注意初始值的设置为表选项,应该放到括号外
mysql> 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
primary key auto_increment,
)engine
=
innodb,auto_increment
=
2
;
步长
=
2
default charset
=
utf8
mysql自增的步长: show session variables like
'auto_inc%'
;
#基于会话级别
清空表:
delete from t1; # 如果有自增id,新增的数据,仍然是以删除前的最后一样作为起始。也即不能清空自增的那个id,新增数据会继续沿用原来排序过来的那个id。
delete是用来删除固定范围的一些数据,比如delete from t20 where id = 3;
truncate table t1; # 数据量大,删除速度比上一条快,且直接从零开始,清空表,应该用truncate
⑥foreign key(建立表间关系)
一 ,快速理解foreign key
员工信息表有三个字段:工号 姓名 部门
公司有3个部门,但是有1个亿的员工,那意味着部门这个字段需要重复存储,部门名字越长,越浪费
解决方法:
我们完全可以定义一个部门表
然后让员工信息表关联该表,如何关联,即foreign key
'''外键要求:所关联的字段必须唯一 (要么unique , 要么主键,用来连接2张表,一般为主键) '''
# 1,建立表关系,先建被关联的表,并且保证被关联的字段唯一
# 表类型必须是innodb存储引擎,且被关联的字段,
即references指定的另外一个表的字段,必须保证唯一
mysql> create table department( -> id int primary key, -> name varchar(20) not null -> )engine=innodb; Query OK, 0 rows affected (0.03 sec) # 2,再建立关联的表#dpt_id外键,关联父表(department主键id),同步更新,同步删除,
# 不增加同步更新和同步删除的话也是可以创建的,只是不能更新和创建的。
mysql> create table employee( -> id int primary key, -> name varchar(20) not null, -> dpt_id int, -> constraint fk_name foreign key(dpt_id) references department(id) -> on delete cascade # 增加删除同步权限 -> on update cascade # 增加更新同步权限 -> )engine=innodb; Query OK, 0 rows affected (0.02 sec) #先往父表department中插入记录 mysql> insert into department values -> (1,'欧德博爱技术有限事业部'), -> (2,'艾利克斯人力资源部'), -> (3,'销售部'); Query OK, 3 rows affected (0.00 sec) Records: 3 Duplicates: 0 Warnings: 0 mysql> insert into employee values -> (1,'egon',1), -> (2,'alex1',2), -> (3,'alex2',2), -> (4,'alex3',2), -> (5,'李坦克',3), -> (6,'刘飞机',3), -> (7,'张火箭',3), -> (8,'林子弹',3), -> (9,'加特林',3) -> ; Query OK, 9 rows affected (0.00 sec) Records: 9 Duplicates: 0 Warnings: 0 mysql> desc department; +-------+-------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +-------+-------------+------+-----+---------+-------+ | id | int(11) | NO | PRI | NULL | | | name | varchar(20) | NO | | NULL | | +-------+-------------+------+-----+---------+-------+ 2 rows in set (0.00 sec) mysql> select * from department; +----+-----------------------------------+ | id | name | +----+-----------------------------------+ | 1 | 欧德博爱技术有限事业部 | | 2 | 艾利克斯人力资源部 | | 3 | 销售部 | +----+-----------------------------------+ 3 rows in set (0.00 sec) mysql> select * from employee; +----+-----------+--------+ | id | name | dpt_id | +----+-----------+--------+ | 1 | egon | 1 | | 2 | alex1 | 2 | | 3 | alex2 | 2 | | 4 | alex3 | 2 | | 5 | 李坦克 | 3 | | 6 | 刘飞机 | 3 | | 7 | 张火箭 | 3 | | 8 | 林子弹 | 3 | | 9 | 加特林 | 3 | +----+-----------+--------+ 9 rows in set (0.00 sec) #删父表department,子表employee中对应的记录跟着删 mysql> delete from department where id=3; Query OK, 1 row affected (0.01 sec) mysql> select * from employee; +----+-------+--------+ | id | name | dpt_id | +----+-------+--------+ | 1 | egon | 1 | | 2 | alex1 | 2 | | 3 | alex2 | 2 | | 4 | alex3 | 2 | +----+-------+--------+ 4 rows in set (0.00 sec)
#更新父表department,子表employee中对应的记录跟着改 mysql> update department set id=222 where id=2; Query OK, 1 row affected (0.01 sec) Rows matched: 1 Changed: 1 Warnings: 0 mysql> select * from employee; +----+-------+--------+ | id | name | dpt_id | +----+-------+--------+ | 1 | egon | 1 | | 2 | alex1 | 222 | | 3 | alex2 | 222 | | 4 | alex3 | 222 | +----+-------+--------+ 4 rows in set (0.00 sec)
二,如何找出两张表之间的关系
分析步骤: #1、先站在左表的角度去找 是否左表的多条记录可以对应右表的一条记录,如果是,则证明左表的一个字段foreign key 右表一个字段(通常是id) #2、再站在右表的角度去找 是否右表的多条记录可以对应左表的一条记录,如果是,则证明右表的一个字段foreign key 左表一个字段(通常是id) #3、总结: #多对一: 如果只有步骤1成立,则是左表多对一右表 如果只有步骤2成立,则是右表多对一左表 #多对多 如果步骤1和2同时成立,则证明这两张表时一个双向的多对一,即多对多,需要定义一个这两张表的关系表来专门存放二者的关系
三,建立表之间的关系
实际上自己建立表关系的时候不要建立这种表之间的关系,易搞混乱,下面是一个实例。
#一对多或称为多对一 三张表:出版社,作者信息,书 一对多(或多对一):一个出版社可以出版多本书 关联方式:foreign key
建立多对一的关系(press为一,book为多)
mysql> create table press( -> id int primary key auto_increment, -> name varchar(20) -> ); Query OK, 0 rows affected (0.03 sec) mysql> create table book( -> id int primary key auto_increment, -> name varchar(20), -> press_id int not unll, -> foreign key(press_id) references press(id) -> on delete cascade -> on update cascade -> ); mysql> insert into press(name) values -> ('工业机械出版社'), -> ('北京大学出版社'), -> ('新华字典出版社') -> ; Query OK, 3 rows affected (0.02 sec) Records: 3 Duplicates: 0 Warnings: 0 mysql> insert into book(name,press_id) values -> ('谁的人生不迷茫',1), -> ('追风筝的人',2), -> ('西游记','2'), -> ('三体',3), -> ('活着',2), -> ('人性的弱点',3); Query OK, 6 rows affected (0.06 sec) Records: 6 Duplicates: 0 Warnings: 0 mysql> select * from book; +----+-----------------------+----------+ | id | name | press_id | +----+-----------------------+----------+ | 1 | 谁的人生不迷茫 | 1 | | 2 | 追风筝的人 | 2 | | 3 | 西游记 | 2 | | 4 | 三体 | 3 | | 5 | 活着 | 2 | | 6 | 人性的弱点 | 3 | +----+-----------------------+----------+ 6 rows in set (0.00 sec) mysql> select * from press; +----+-----------------------+ | id | name | +----+-----------------------+ | 1 | 工业机械出版社 | | 2 | 北京大学出版社 | | 3 | 新华字典出版社 | +----+-----------------------+ 3 rows in set (0.00 sec)
另一种正常思维创建:课上讲解的代码 ## 哈哈 其实和上面的是一样的只是创建第一个表的时候 上面的序号是自动生成的由于设置是primary key auto_increment
student1: id name age classname 1 wangwen 17 python5 2 majuqiang 98 python5 3 zhangguocheng 97 python5 4 yisi 100 python5 5 zhangsan 45 python6 5 zhangs 35 python6 # 出现过多冗余的数据,开始分表,利用外键关联 student1: id name age 1 wangwen 18 2 maju 19 3 cheng 18 class1: id classname 1 python5 2 python6 # 先创建class1 表 create table class1(id int,classname varchar(255)); # 创建学生表,创建外键(一般会把外键设置在一对多,多的那张表上面) # foreign key(class_id) references class1(id) create table student1(id int primary key auto_increment, name varchar(255), age int,class_id int, oreign key(class_id) references class1(id)) # 设置id为unique alter table class1 add unique(id); # 插入数据 insert into class1 values(1,"python5"); insert into class1 values(2,"python6"); insert into student1 values(null,"aa",13,1); insert into student1 values(null,"aa",13,2); # ->删除的是不带外键的那张表,会拒绝删除
# 如果要增加可删除 可修改的参数的话 必须在references class(id) 下面
添加
-> on delete cascade
-> on update cascade
建立多对多的关系
=====================多对多===================== 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) # constraint fk_author 为foreign key取个名字 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 一对一且不重复
小结:
一个学生对应多个学科,一个学科可以对应多个学生 , 一本书可以对应多个作者,一个作者也可以写多本书
如果存在多对多的关系,要单独创建关系表,。
一对一
里面的foreign key里面一定要加上unique,确保一对一且唯一。
#一定是student来foreign key表customer,这样就保证了:
#1 学生一定是一个客户,
#2 客户不一定是学生,但有可能成为一个学生
mysql> create table customer( -> id int primary key auto_increment, -> name varchar(20) not null, -> qq varchar(10) not null, -> phone char(16) not null -> ); Query OK, 0 rows affected (0.02 sec) mysql> 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 -> ); Query OK, 0 rows affected (0.02 sec) mysql> insert into customer(name,qq,phone) values -> ('李飞机','31811231',13811341220), -> ('王大炮','123123123',15213146809), -> ('守榴弹','283818181',1867141331), -> ('吴坦克','283818181',1851143312), -> ('赢火箭','888818181',1861243314), -> ('战地雷','112312312',18811431230) -> ; Query OK, 6 rows affected (0.00 sec) Records: 6 Duplicates: 0 Warnings: 0 mysql> insert into student(class_name,customer_id) values -> ('脱产3班',3), -> ('周末19期',4), -> ('周末19期',5) -> ; Query OK, 3 rows affected (0.01 sec) Records: 3 Duplicates: 0 Warnings: 0 mysql> select * from student; +----+-------------+-------------+ | id | class_name | customer_id | +----+-------------+-------------+ | 1 | 脱产3班 | 3 | | 2 | 周末19期 | 4 | | 3 | 周末19期 | 5 | +----+-------------+-------------+ 3 rows in set (0.00 sec) mysql> select * from customer; +----+-----------+-----------+-------------+ | id | name | qq | phone | +----+-----------+-----------+-------------+ | 1 | 李飞机 | 31811231 | 13811341220 | | 2 | 王大炮 | 123123123 | 15213146809 | | 3 | 守榴弹 | 283818181 | 1867141331 | | 4 | 吴坦克 | 283818181 | 1851143312 | | 5 | 赢火箭 | 888818181 | 1861243314 | | 6 | 战地雷 | 112312312 | 18811431230 | +----+-----------+-----------+-------------+ 6 rows in set (0.00 sec)
7.数据的操作
注意:前面其实已经介绍过了,现在只是重复一下。
1,数据的增删改查
MySQL数据操作: DML 在MySQL管理软件中,可以通过SQL语句中的DML语言来实现数据的操作,包括 1,使用INSERT实现数据的插入 2,UPDATE实现数据的更新 3,使用DELETE实现数据的删除 4,使用SELECT查询数据以及。
插入数据:
1. 插入完整数据(顺序插入) 语法一: INSERT INTO 表名(字段1,字段2,字段3…字段n) VALUES(值1,值2,值3…值n); 语法二: INSERT INTO 表名 VALUES (值1,值2,值3…值n); # 如果要在表中插入定义的所有数据 可以不用 在表名后面把所有的字段都写出来。 2. 指定字段插入数据 语法: INSERT INTO 表名(字段1,字段3…) VALUES (值1,值2…); 3. 插入多条记录 语法: INSERT INTO 表名 VALUES (值1,值2,值3…值n), (值1,值2,值3…值n), (值1,值2,值3…值n); 4. 插入查询结果 语法: INSERT INTO 表名(字段1,字段2,字段3…字段n) SELECT (字段1,字段2,字段3…字段n) FROM 表2 WHERE …;
insert into 表名(字段1,字段2) select (字段1,字段2) from ... where...
更新数据:
语法: UPDATE 表名 SET 字段1=值1, 字段2=值2, WHERE CONDITION; 示例: UPDATE mysql.user SET password=password(‘123’) where user=’root’ and host=’localhost’;
删除数据DELETE
语法:
DELETE FROM 表名
WHERE CONITION;
示例:
DELETE FROM mysql.user
WHERE password=’’;
2.单表查询
2.1简单查询
2.2WHERE约束
比较运算符:><>= <= <> != between 80 and 100 值在10到20之间 in(80,90,100) 值是10或20或30 模糊匹配:like 'qiuma%' pattern可以是%或_, %表示任意多字符 _表示一个字符 逻辑运算符:在多个条件直接可以使用逻辑运算符 and or not
like 模糊查询 like '%' 通配符 匹配任意长度任意字符
like '%a' 以a结尾的任意长度字符串
like 'a%' 以a开头的任意长度字符串
like '%a%' 匹配中间带个a的字符串
like '_a' 一共2个长度,以a结尾,字符无所谓
like 'a__' 一共3个长度,以a开头,后面字符无所谓
# 注意之前建好表格。
# (1) 单条件查询: # 查询部门是sale的所有员工姓名: select emp_name from employee where post = 'sale'; # (2)多条件查询 # 部门是teacher , 收入大于10000 select name,salary from employee where post="teacher" and salary >10000; # 显示结果不同而已 select * from employee where post="teacher" and salary>10000; # (3)关键字 between .. and .. # 收入在1万和2万之间的姓名和收入 select emp_name,salary from employee where salary between 10000 and 20000; # 收入不再1万和2万之间的 select emp_name,salary from employee where salary not between 10000 and 20000; # (4) 关键字is null(判断某个字段是否为null 不能用等号 用is) #查询post_comment 是空的 select emp_name,post_comment from employee where post_comment is null; #查询post_comment 不是空的 select emp_name,post_comment from employee where post_comment is not null; #查询post_comment 是空字符串 select emp_name,post_comment from employee where post_comment = "";执行的时候注意表格中post_comment 的内容不是空的话记得是设置一下;
update employee
set
post_comment
=
'' where
id
=
2
;
再用上条查看,就会有结果了
# 设置一个值是空; update employee set post_comment= '' where id = 2; # (5) 关键字in集合查询 # 查收入是3000 或者3500或者4000或者9000所有的员工和收入 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); # 不再这个范围里 float 的精度判断? select emp_name,salary from employee where salary not in (3000,3500,4000,9000,3000.99); # (6) 关键字like的模糊查询 # (1) 通配符'%' select * from employee where emp_name like 'eg%'; # (2) 通配符'_' select * from employee where emp_name like 'al__'; # (7) sql 函数concat(参数1,参数2,参数3) 把所有参数拼接在一起 # concat_ws("符号",参数1,参数,参数3.....) # sql 中可以做四则运算(加减乘除) # as 用来起别名 select emp_name,concat("姓名:",emp_name,"薪水:",salary) as my_s from employee; select emp_name,concat("姓名:",emp_name,"薪水:",salary*12) as my_s from employee; # 第一个参数是分隔符,后面依次写上要拼接的值; select emp_name,concat_ws(" : ",emp_name,salary*12) as my_s from employee;
2.3,GROUP BY:分组查询
1,为何分组? 1、首先明确一点:分组发生在where之后,即分组是基于where之后得到的记录而进行的,因此,如果有where,分组group by是一定放在where后面执行的。 2、分组指的是:将所有记录按照某个相同字段进行归类,比如针对员工信息表的职位分组,或者按照性别进行分组等,且分组之后只能取分组的字段,以及每个组聚合结果。 3、为何要分组呢? 取每个部门的最高工资 取每个部门的员工数 取男人数和女人数 小窍门:‘每’这个字后面的字段,就是我们分组的依据 4、大前提: 可以按照任意字段分组,但是分组完毕后,比如group by post,只能查看post字段,如果想查看组内信息,需要借助于聚合函数
select office from employee where depart_id > 1 group by office; # 函数: group_concat() 对分组的内容进行拼接; select group_concat(emp_name),post from employee group by post; select group_concat(emp_name),post from employee where depart_id >1 group by post # 聚合函数: # count(*) : 统计总数 select count(*) from employee; select count(*) from employee where depart_id = 1; # 统计最大值 max select max(salary) from employee; # 统计最小值 min select min(salary) from employee; # 统计平均值 avg select avg(salary) from employee; # 统计总和 sum select sum(salary) from employee; # 分组 + 聚合函数 一起使用 # 求各部门的平均工资 select post,avg(salary),group_concat(emp_name) from employee group by post; # 求各部门薪资的最大值 select post,avg(salary),group_concat(emp_name) from employee group by post;
2.4,过滤HAVING
'''执行过程:先执行where 在执行group by 等数据搜出来了再用having过滤的;''' # 比如:求部门的平均薪资,在10000以上的所有部门 select post from employee group by post having avg(salary) > 10000; # 1查询各岗位内包含的员工个数小于2的 岗位名、岗位内包含员工名字、个数 select post,group_concat(emp_name),count(*) from employee group by post having count(*) <2; # 2.查询各岗位平均薪资大于10000的岗位名、平均工资 select post,avg(salary) from employee group by post having avg(salary) > 10000; #3查询各岗位平均薪资大于10000且小于20000的岗位名、平均工资 #(1) select post,avg(salary) from employee group by post having avg(salary) > 10000 and avg(salary) < 20000; #(2) select post,avg(salary) from employee group by post having avg(salary) between 10000 and 20000;
2.5查询排序:ORDER BY
# 默认升序asc 从小到大排序 select emp_name,age from employee where post = "teacher" order by age; # 降序 desc 从大到小排序 select emp_name,age from employee where post = "teacher" order by age desc;
排列顺序
1.找到表:from 2.拿着where指定的约束条件,去文件/表中取出一条条记录 3.将取出的一条条记录进行分组group by,如果没有group by,则整体作为一组 4.将分组的结果进行having过滤 5.执行select 6.去重 7.将结果按条件排序:order by 8.限制结果的显示条数
select post,count(id) as emp_count from employee where salary > 1000 group by post having count(id) > 1 order by count(id) desc # 此处不能用emp_count代替count(id),因为是先运行emp_count,再运行count(id)
2.6 限制查询的记录数:LIMIT
# 查询最后一条数据 select * from employee order by id desc limit 1;
·# 倒数三条 select * from employee order by id desc limit 3; # limit(m,n) 默认m的值是0 代表第一条数据,n所代表的是查询几条,从的m+1条数据开始,查询n条数据; select * from employee limit 0,5 select * from employee limit 5,5 select * from employee limit 10,5
2.7 使用正则表达式查询
select * from employee where emp_name regexp '^ale.*'; select * from employee where emp_name regexp 'on$'; select * from employee where salary regexp '0{3}'; # 用like来取代 select * from employee where emp_name like 'yuan%';
3.总结(顺序 重点)
单表查询的语法顺序与执行顺序总结
①语法顺序
SELECT distinct(可加可不加,去重)字段1,字段2... FROM 库,表名
WHERE 条件
GROUP BY field(分组条件)
HAVING 筛选,过滤
ORDER BY field
LIMIT 限制条数
②执行顺序(重点中的重点)
重点中的重点:关键字的执行优先级 from where group by having select distinct order by limit
3.多表查询
1.内连接
#内连接(内联查询 inner join) : 两表或多表中条件同时满足,查询数据 ''' 语法: select 字段 from 表1 inner join 表2 on 条件 多表: select 字段 from 表1 inner join 表2 on 条件 inner join 表3 on 条件 inner join 表4 on 条件... .... '''
select * from employee inner join department on employee.dep_id = department.id;
# 用as 起别名 as 可以省略
select * from employee as emp inner join department as dep on emp.dep_id = dep.id;
select * from employee emp inner join department dep on emp.dep_id = dep.id;
mysql> select * from employee inner join department on employee.dep_id = department.id; +----+-----------+--------+------+--------+------+--------------+ | id | name | sex | age | dep_id | id | name | +----+-----------+--------+------+--------+------+--------------+ | 1 | egon | male | 18 | 200 | 200 | 技术 | | 2 | alex | female | 48 | 201 | 201 | 人力资源 | | 3 | wupeiqi | male | 38 | 201 | 201 | 人力资源 | | 4 | yuanhao | female | 28 | 202 | 202 | 销售 | | 5 | liwenzhou | male | 18 | 200 | 200 | 技术 | +----+-----------+--------+------+--------+------+--------------+ 5 rows in set (0.00 sec) mysql> select * from employee as emp inner join -> department as dep on -> emp.dep_id = dep.id; +----+-----------+--------+------+--------+------+--------------+ | id | name | sex | age | dep_id | id | name | +----+-----------+--------+------+--------+------+--------------+ | 1 | egon | male | 18 | 200 | 200 | 技术 | | 2 | alex | female | 48 | 201 | 201 | 人力资源 | | 3 | wupeiqi | male | 38 | 201 | 201 | 人力资源 | | 4 | yuanhao | female | 28 | 202 | 202 | 销售 | | 5 | liwenzhou | male | 18 | 200 | 200 | 技术 | +----+-----------+--------+------+--------+------+--------------+ 5 rows in set (0.00 sec)
第三种把:第二种中的as去掉。
不
小结:三种方式创建都是合理的,只是2个给该表起了别名,另外一个没有取别名。
# 普通的where 条件来写; 默认内联
select * from employee emp,department dep where emp.dep_id = dep.id; mysql> select * from employee inner join department on employee.dep_id = department.id; +----+-----------+--------+------+--------+------+--------------+ | id | name | sex | age | dep_id | id | name | +----+-----------+--------+------+--------+------+--------------+ | 1 | egon | male | 18 | 200 | 200 | 技术 | | 2 | alex | female | 48 | 201 | 201 | 人力资源 | | 3 | wupeiqi | male | 38 | 201 | 201 | 人力资源 | | 4 | yuanhao | female | 28 | 202 | 202 | 销售 | | 5 | liwenzhou | male | 18 | 200 | 200 | 技术 | +----+-----------+--------+------+--------+------+--------------+ 5 rows in set (0.00 sec)
小结:按照查两张表思路就行查询,上面的内联方式可以说是合成的是一张表,然后就行查询,普通方式是直接在指定位置查询该表。
2. 外连接
# (1) 左连接(左联查询left join) : 以左表为主,右表为辅,完整查询左表数据,右表对不上的补null """语法: select 字段 from 表1 left join 表2 on 条件"""
select * from employee emp left join department dep on emp.dep_id = dep.id mysql> select * from employee emp left join department dep on emp.dep_id=dep.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 | +----+------------+--------+------+--------+------+--------------+ 6 rows in set (0.00 sec)
# (2) 右连接(右联查询right join) """语法: select 字段 from 表1 right join 表2 on 条件"""
select * from employee emp right join department dep on emp.dep_id = dep.id mysql> select * from employee emp right join department dep on emp.dep_id=dep.id; +------+-----------+--------+------+--------+------+--------------+ | id | name | sex | age | dep_id | id | name | +------+-----------+--------+------+--------+------+--------------+ | 1 | egon | male | 18 | 200 | 200 | 技术 | | 2 | alex | female | 48 | 201 | 201 | 人力资源 | | 3 | wupeiqi | male | 38 | 201 | 201 | 人力资源 | | 4 | yuanhao | female | 28 | 202 | 202 | 销售 | | 5 | liwenzhou | male | 18 | 200 | 200 | 技术 | | NULL | NULL | NULL | NULL | NULL | 203 | 运营 | +------+-----------+--------+------+--------+------+--------------+ 6 rows in set (0.00 sec)
3.全连接
select * from employee emp left join department dep on emp.dep_id = dep.id union select * from employee emp right join department dep on emp.dep_id = dep.id mysql> select * from employee emp left join department dep on emp.dep_id=dep.id -> union -> select * from employee emp right join department dep on emp.dep_id=dep.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 | 运营 | +------+------------+--------+------+--------+------+--------------+ 7 rows in set (0.00 sec)
小结:全连接的话就是把左连接的内容和右连接的内容就行一个关键字union的拼接形成的。
# 例1:
# 找出年龄大于25岁的员工以及员工所在的部门
分析:首先是部门 要编号 还是名字
1.要编号
# 找出年龄大于25岁的员工以及员工所在的部门 方式1: select employee.id,employee.name,department.name from employee inner join department on employee.dep_id = department.id where age > 25; +----+---------+--------------+ | id | name | name | +----+---------+--------------+ | 2 | alex | 人力资源 | | 3 | wupeiqi | 人力资源 | | 4 | yuanhao | 销售 | +----+---------+--------------+ 方式2: select employee.id,employee.name as ename,department.name as dname from employee inner join department on employee.dep_id = department.id where age > 25; +----+---------+--------------+ | id | ename | dname | +----+---------+--------------+ | 2 | alex | 人力资源 | | 3 | wupeiqi | 人力资源 | | 4 | yuanhao | 销售 | +----+---------+--------------+ 3 rows in set (0.00 sec)
例2:
以内连接的方式查询employee 和 department 表数据,以age字段升序排序;
select emp.id,emp.name,dep.name ,emp.age from employee as emp,department as dep where emp.dep_id = dep.id order by age asc; # 其中默认的就是升序 +----+-----------+--------------+------+ | id | name | name | age | +----+-----------+--------------+------+ | 1 | egon | 技术 | 18 | | 5 | liwenzhou | 技术 | 18 | | 4 | yuanhao | 销售 | 28 | | 3 | wupeiqi | 人力资源 | 38 | | 2 | alex | 人力资源 | 48 | +----+-----------+--------------+------+ # 内联: select emp.id,emp.name,dep.name ,emp.age from employee as emp inner join department as dep on emp.dep_id = dep.id order by age desc; +----+-----------+--------------+------+ | id | name | name | age | +----+-----------+--------------+------+ | 2 | alex | 人力资源 | 48 | | 3 | wupeiqi | 人力资源 | 38 | | 4 | yuanhao | 销售 | 28 | | 1 | egon | 技术 | 18 | | 5 | liwenzhou | 技术 | 18 | +----+-----------+--------------+------+
4.子查询
# 子查询:sql语句嵌套 1.子查询是将一个查询语句嵌套在另一个查询语句中,用括号()包起来,表达一个整体 2.一般应用在from 和 where 子句当中 3.内层sql语句可以作为外层sql语句查询条件,也可以是表 4.速度从快~ 慢 单表查询速度最快 > 其次是联表操作 > 子查询 5.子查询中可以包含一些符号,> < >= <= == != is not in not in exists关键字 ....
# (1)找出平均年龄大于25岁以上的部门;
# 普通写法: select d.name,avg(age) from employee e,department d where e.dep_id = d.id group by d.name having avg(age)>25; +--------------+----------+ | name | avg(age) | +--------------+----------+ | 人力资源 | 43.0000 | | 销售 | 28.0000 | +--------------+----------+
普通方法:(第一步)
分析:1. from from enployee e, department d 从这两个表当中提取数据(从什么地方提取数据,普通方法的是将所有表直接写出来,没有使用什么inner join等等什么的,
其他方式需要考虑要得到的数据分别来自什么地方就行灵活变动,比如这题是需要的是部门的名字,其在第二张表当中需要一些指令就行把2张表就行合并一下,普通方法中只需要where 条件就可以了,
)
2. where条件 e.dep_id = d.id 运行之后得到的是合并的两张表
3. group 分组 由于要的是部分 group by d.name
4. having 把整个数据过滤一下 having avg(age) > 25
5. select 提取我们需要的信息。
6.order by ....
7. limit (限制查询的条数)
理解这样的过程就会很简单的写出来。
# 内联写法:
# 要部门id 其实需要的是部门id的话可以不将内联的方式将两张表就行合并在一起。 select dep_id,avg(age) from employee emp inner join department dep on emp.dep_id =dep.id group by dep.id having avg(age) > 25; +--------+----------+ | dep_id | avg(age) | +--------+----------+ | 200 | 18.0000 | | 201 | 43.0000 | | 202 | 28.0000 | +--------+----------+ 3 rows in set (0.00 sec)
小结:内联写法相当于直接把两张表使用
employee emp inner join department dep on emp.dep_id =dep.id
这个搞成一个表,而普通的方法1,是通过
employee e,department d where e.dep_id = d.id
条件将,两张表搞成一张表的。
# 方法二 需要的是部门的名字,如果是只需要部门的id,可以是表1中的id或者是表二种的id
select dep.name,avg(age) from employee emp inner join department dep on emp.dep_id =dep.id group by dep.name having avg(age) > 25; +--------------+----------+ | name | avg(age) | +--------------+----------+ | 人力资源 | 43.0000 | | 销售 | 28.0000 | +--------------+----------+ 2 rows in set (0.00 sec)
(2) 筛选部门平均年龄大于25岁的部门名字
分析: 1.from 2.where 条件 3.分组 4.having 5,select 拿出数据 6.inder by xx 排序 7.limit 查询的个数 要什么数据:部门名字、然后大于25岁在部门名字那张表没有办法搞定即是需要创建2张表合并的表。 select dep.name 1. from employee emp inner join department on emp.dep_id=dep.id
注意:个人觉得 on emp.dep_id=dep.id 和where出差不多 分组:由于需要部门的平均年龄还是需要 2.group by dep.name 3.having :avg(age) > 25
# 内联写法:
# 可以不用显示avg(age)
select dep.name,avg(age) from employee emp inner join department dep on emp.dep_id =dep.id group by dep.name having avg(age) > 25; +--------------+----------+ | name | avg(age) | +--------------+----------+ | 人力资源 | 43.0000 | | 销售 | 28.0000 | +--------------+----------+ 2 rows in set (0.00 sec
查询语句作为另一个查询语句中的字段
# 用子查询的方式写:
# .子查询是将一个查询语句嵌套在另一个查询语句中,用括号()包起来,表达一个整体
# 筛选部分平均年龄大于25岁的部门名字
分析:找出要查询的东西和表与表之间的关系。
表1 和表2 之间的相关的其实就是id,只需要把满足条件的东西,拿出来去第二张表中查就可以。
比如1.先在表1中把满足条件的id选出来,去表2中再查一次就可以啦。
2.
# 如果只需要id的话一张表的内容就可以搞定
# 筛选出201 202
select dep_id from employee group by dep_id having avg(age) > 25 +--------+ | dep_id | +--------+ | 201 | | 202 | +--------+
# 在按照结果赛选,选出id在201 和 202 之间的所有范围内数据 select name from department where id in (201,202) # 最终子查询版本 select name from department where id in (select dep_id from employee group by dep_id having avg(age) > 25); +--------------+ | name | +--------------+ | 人力资源 | | 销售 | +--------------+
5.例子
5.1查看技术部门所有员工的姓名.
要什么:员工的姓名(来自于表1),技术部门(字样)来自于表2 # 内联写法 select emp.name,emp.name 1.from from emlopyee emp inner join department dep on emp.dep_id=dep.id 2.where 条件 where dep.name="技术" 3.分组 group by 不需要 4. having 不需要 5.select.. 6.order by 不需要 7.limit 不需要 组合写法: select emp.name,emp.name from emlopyee emp inner join department dep on where dep.name="技术" ;
# 内联查询: select d.name,e.name from employee as e inner join department as d on e.dep_id = d.id where d.name="技术"; +--------+-----------+ | name | name | +--------+-----------+ | 技术 | egon | | 技术 | liwenzhou | +--------+-----------+ 2 rows in set (0.00 sec) # 子查询
# 普通方法:(联表查询) select e.name, d.name from employee e,department d where e.dep_id=d.id and d.name="技术"; select e.name,d.name from employee as e , department as d where e.dep_id = d.id and d.name="技术" +--------+-----------+ | name | name | +--------+-----------+ | 技术 | egon | | 技术 | liwenzhou | +--------+-----------+ 2 rows in set (0.00 sec)
# 子查询写法 要什么:技术部门的名字(来自于表2)和 技术部门员工的名字(来自于表1) # 子查询个人理解为嵌套的查询 即是先查询什么 然后在查询什么的结果 1.先去表2中查出技术部门的id,燃后去查询表1中name,表2中查询出的结果作为条件 (1)select id from department where name = "技术"; (2)select name from employee dep_id = ? (3)select name from employee where dep_id = (select id from department where name = "技术") +-----------+ | name | +-----------+ | egon | | liwenzhou | +-----------+
5.2查看哪个部门没员工?
# 内联写法 要什么:部门的名字 select dep.name 1.from from employee emp right join department dep 2.where 条件 无 有个类似的 on emp.dep_id = dep.id 3.group by 分组 不需要,不要以整个部门为整体的操作 4.having 过滤出 dep.id is null的(right是以右边的表为主,即是岗位上没人的地方全部补上null) 5.select 拿出所要的数据 6.order by 无 7.limit 无 总写:select d.id,d.name from employee e right join department d on e.dep_id = d.id where e.dep_id is null # 子查询方法2 # (1) 先来查询所有员工部门的种类 select dep_id from employee group by dep_id; # (2) 查询department select id from department where id not in ? # (3) 综合 select id from department where id not in (select dep_id from employee group by dep_id) +------+ | id | +------+ | 203 | +------+
小结:子查询,只能得到一个表中的数据,相当于你从表二种得到的数据,然后去表1 中再次将表2查到的数据 无论你是拿来作为select 还是where 还是 字段都是可以的,也即是查到的是表1 的数据。
5.3查询大于平均年龄的员工名与年龄
要什么:员工名字(表1),员工年龄(表1),平均值也是不知道的但是在做比较的时候会利用到,于是必须先求出来 1.先将平均年龄查出来,作为条件使用 2.再在表1 中按照条件就行查出员工名字和年龄。 select name,dep_id from employee where avg(age) >(select avg(age) from employee) select avg(age) from employee; # 先查询一下字句得到一个平均值,基于这个值在查询第二次 select name , age from employee where age > (select avg(age) from employee); +---------+------+ | name | age | +---------+------+ | alex | 48 | | wupeiqi | 38 | +---------+------+ 小结:# avg 聚合函数可以直接加在select 后面使用,如果放在其他字句后面,会要求分组group by
5.4把大于其本部门平均年龄的员工名和姓名查出来
要什么:员工名字(表1) 姓名(表1) 条件:大于本部门的平均年龄 1.本部分平均年龄:需要查询的是部门和平均年龄 2.在查出的各部门的平均年龄之后,需要在再一次查询,由于表1中想要限制2个条件是不可能的,于是就利用子查询的结果与原表就行结合查询。就行员工的年龄个平均年龄作比较并得到最小的人。 select dep_id, avg(age) from employee group by dep_id; 2. select * from employee t1 inner join (select dep_id, avg(age) as age from employee group by dep_id) as t2 on t1.dep_id = t2.dep_id where t1.age > t2.age
5.5 查询每个部门最新入职的那位员工
要什么:select * 条件 每个部门最新入职 # 每个部门都对应很多员工,每个员工有对应很多时间.这个时间如果最大就代表刚入职的; select post,max(hire_date) from employee group by post; # 将得到的表1和表2就行凭借。 select * from employee as t1 inner join (select post,max(hire_date) as max_date from employee group by post) as t2 on t1.post = t2.post where t1.hire_date = t2.max_date +----+--------+--------+-----+------------+-----------------------------------------+--------------+------------+--------+-----------+-----------------------------------------+------------+ | id | name | sex | age | hire_date | post | post_comment | salary | office | depart_id | post | max_date | +----+--------+--------+-----+------------+-----------------------------------------+--------------+------------+--------+-----------+-----------------------------------------+------------+ | 1 | egon | male | 18 | 2017-03-01 | 驻沙河办事处外交大使 | NULL | 7300.33 | 401 | 1 | 老男孩驻沙河办事处外交大使 | 2017-03-01 | | 2 | alex | male | 78 | 2015-03-02 | teacher | NULL | 1000000.31 | 401 | 1 | teacher | 2015-03-02 | | 13 | 格格 | female | 28 | 2017-01-27 | sale | NULL | 4000.33 | 402 | 2 | sale | 2017-01-27 | | 14 | 张野 | male | 28 | 2016-03-11 | operation | NULL | 10000.13 | 403 | 3 | operation | 2016-03-11 | +----+--------+--------+-----+------------+-----------------------------------------+--------------+------------+--------+-----------+-----------------------------------------+------------+ 4 rows in set (0.00 sec)
6.带EXISTS关键字的子查询
exists 关键字表示存在 如果内层sql能够查到数据,返回True ,外层sql执行查询操作 如果内层sql不能查到数据,返回False,外层sql不执行查询操作. select * from employee where exists (select * from department where id = 300) 子查询可以单独作为一个字句, 可以作为一个表,或者某个字段 一般用在where 或者 from 或者 select 后面 你想当成字段还是表要根据sql语句的编写形成 通过查询出来的临时表可以和其他表在重新拼凑成一个更大的表 然后把这个更大的表当成一个单表查询操作,完成任务; 子查询一般都是在缺失某个字段的前提下或者缺失某些数据的时候,才被提出来的; 可以灵活的进行自由拼凑达到目标;