1.1 什么是数据库
数据库是按照数据结构来组织、存储和管理数据的仓库,每个数据库都有一个或多个不同的API用于创建、访问、管理、搜索和复制所保存的数据
1.2 关系型数据库管理系统
我们使用关系型数据库管理系统(RDBMS)来存储和管理大量数据。所谓的关系型数据库,是建立在关系模型基础上的数据库,借助于集合代数等数学概念和方法来处理数据库中的数据。
关系型数据库管理系统(Relational Database Management System)的特点:
- 数据以表格的形式出现
- 每行为各种记录名称
- 每列为记录名称所对应的数据域
- 许多的行和列组成一张表单
- 若干的表组成database
1.3 RDBMS 术语
数据库:数据库是一些关联表的集合
数据表:表是数据的矩阵。在一个数据库中的表看起来像一个简单的电子表格
列:一列(数据元素)包含了相同的数据
行:一行(记录)是一组相关的数据
冗余:存储两倍数据,冗余降低了性能,但提高了数据的安全性
主键:主键是唯一的。一个数据表中只能包含一个主键,可以使用主键来查询数据
外键:用于关联两个表
复合键:复合键(组合键)将多个列作为一个索引键,一般用于复合索引
索引:使用索引可快速访问数据库表中的特定信息。索引是对数据库表中一列或多列的值进行排序的一种结构。类似于书籍的目录。
参照完整性:参照的完整性要求关系中不允许引用不存在的实体。与实体完整性是关系模型必须满足的完整性约束条件,目的是保证数据的一致性。
1.4 安装MySQL数据库
常见的安装方式有:源码安装、二进制RPM包安装、二进制免编译安装
官方网站:https://dev.mysql.com/downloads/mysql/
1.5 SQL语句介绍
结构化查询语言(Structured Query Language)简称SQL,是一种特殊目的的编程语言,是一种数据库查询和程序设计语言,用于存取数据以及查询、更新和管理关系数据库系统
SQL分为三种类型:
- DDL:数据定义语言,用于定义和管理SQL数据库中的所有对象的语言,CREATE、ALTER、DROP、TRUNCATE
- DML:数据操作语言,SQL中处理数据等操作统称为数据操纵语言,SELECT、INSERT、UPDATE、DELETE、CALL、EXPLAIN PLAN、LOCK TABLE
- DCL:数据控制语言,用来授予或回收访问数据库的某种特权,GRANT、REVOKE
1.6 存储引擎
存储引擎说白了就是如何存储数据、如何为存储的数据建立索引和如何更新、查询数据等技术的实现方法。因为在关系数据库中数据的存储是以表的形式存储的,所以存储引擎也可以称为表类型(即存储和操作此表的类型)
MySQL支持的存储引擎有:MyISAM、InnoDB、MEMORY、BLACKHOLE、ARCHIVE等
查看MySQL支持的存储引擎: show engines; 查看正在使用的存储引擎: show variables like 'storage_engine%';
1.7 数据类型
MySQL支持多种数据类型,大致可以分为三类:数值、日期/时间、字符串(字符)、枚举
1、数值类型
数值类型包括严格数值数据类型(INTEGER、SMALLINT、DECIMAL和NUMERIC),以及近似数值数据类型(FLOAT、REAL和DOUBLE PRECISION)
注意:整型默认是有符号的,整型的宽度不会限制数据范围(默认宽度11)
类型 |
大小 |
范围(有符号) |
范围(无符号) |
用途 |
TINYINT |
1 字节(8bit) |
(-128,127) (7的2次方减1) |
(0,255) (8的2次方减1) |
很小的整数值 |
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 字节 |
(-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 字节 |
(-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+2 |
依赖于M和D的值 |
依赖于M和D的值 |
小数值 |
2、日期和时间类型
表示时间值的日期和时间类型为DATETIME、DATE、TIMESTAMP、TIME和YEAR
类型 |
大小 |
范围 |
格式 |
用途 |
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 |
混合日期和时间值,时间戳 |
3、字符串类型
字符串类型指CHAR、VARCHAR、BINARY、VARBINARY、BLOB、TEXT、ENUM和SET
类型 |
大小 |
用途 |
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字节 |
极大文本数据 |
4、枚举类型
枚举类型有单选(enum)、多选(set)
enum 单选 只能在给定的范围内选一个值,如性别 sex 男male/女female
set 多选 在给定的范围内可以选择一个或一个以上的值(爱好1,爱好2,爱好3...)
1.8 基本SQL操作
#数据库 增: create database db1; create database if not exists db1 default charset utf8 collate utf8_general_ci; #不存在则创建,存在则不创建,设置编码集为utf8 查: show databases; #查看所有库 SHOW CREATE DATABASE db1; #查看某个数据库的创建信息 改: alter database db1 charset gbk; #更改数据库编码 删: drop database db1; #表 切换到对用库:use db1 增: create table t1(id int,name char(10)); create table t1(id int,name char(10)) engine=innodb; create table t3(id int,name char(10)) engine=innodb default charset utf8; 查: show tables; show create table t1; desc t1; #查看表结构 改: alter table t1 add age int; alter table t1 drop age; alter table t1 modify name char(4); # modify只能改字段类型 alter table t1 change name Name char(4); 删: drop table t1; #记录 增: insert into db1.t1 values(1,'Yim'),(2,'Jim'); 查: select * from t1; select name from t1; 改: update t1 set name='yim' where id=1; #记得加条件! 删: delete from t1 where id=2; truncate table t1; #删除整表记录 delete from t1; #删除整表记录,不会更新自增ID,不要用!
1.9 库操作
1、创建数据库:
create database 数据库名 charset utf8;
2、数据库命名规则
可以由字母、数字、下划线、@、#、$ 区分大小写 唯一性 不能使用关键字如 create select 不能单独使用数字 最长128位
3、数据库相关操作
查看数据库: show databases; show create database 数据库名; select database(); 选择数据库: use 数据库名 删除数据库: drop database 数据库名; 修改数据库: alter database 数据库名 charset utf8;
1.10 表操作
1.10.1 基本操作
1、创建表
create table 表名(
字段名1 类型[(宽度) 约束条件],
字段名2 类型[(宽度) 约束条件]
);
2、查看表结构
desc 表名;
show create table 表名\G #查看表详细结构
3、修改表
#修改表名
alter table 表名 rename 新表名;
#增加字段
alter table 表名 add 字段名 数据类型 [完整性约束条件…];
alter table 表名 add 字段名 数据类型 [完整性约束条件…] first; #添加到最前面
alter table 表名 add 字段名 数据类型 [完整性约束条件…] after 字段名; #添加到某字段之后
#删除字段
alter table 表名 drop 字段名;
#修改字段(modify只能改字段类型)
alter table 表名 modify字段名 数据类型 [完整性约束条件…];
alter table 表名 change旧字段名 新字段名 旧数据类型 [完整性约束条件…];
alter table 表名 change旧字段名 新字段名 新数据类型 [完整性约束条件…];
修改表的例子:
#修改表存储引擎 mysql> alter table t1 engine=myisam; #添加字段 mysql> alter table emp add sex char(6) not null; mysql> alter table emp add tel char(11) not null after age; #添加age字段之后 mysql> alter table emp add addr char(50) not null first; #添加到最前面 #删除字段 mysql> alter table emp drop addr; #修改字段类型 mysql> alter table emp modify age int(3); #增加约束(针对已有的主键增加auto_increment) mysql> alter table emp modify id int(11) not null auto_increment; #针对已存在的表增加复合主键 mysql> alter table service add primary key(host_ip,port); #增加主键 mysql> alter table t2 modify id int not null primary key; #增加主键和自增 mysql> alter table t3 modify id int not null primary key auto_increment; #删除主键 mysql> alter table t3 modify id int not null; #删除自增 mysql> alter table t3 drop primary key; #删除主键 #修改字段名 mysql> alter table t3 change name Name char(16);
4、复制表
#复制表结构+记录 (key不会复制: 主键、外键和索引) mysql> create table user select * from mysql.user; #只复制表结构 mysql> create table user_2 select * from mysql.user where 1=2; #条件为假,查不到任何记录
5、删除表
#删除表 drop table 表名; #删除表的所有记录 truncate table 表名; #删除整表记录 delete from 表名; #删除整表记录,不会更新自增ID,不要用!
1.10.2 约束条件
1、介绍
约束条件与数据类型的宽度一样,都是可选参数
主要分为:
PRIMARY KEY (PK) 标识该字段为该表的主键,可以唯一的标识记录 FOREIGN KEY (FK) 标识该字段为该表的外键 NOT NULL 标识该字段不能为空 UNIQUE KEY (UK) 标识该字段的值是唯一的 AUTO_INCREMENT 标识该字段的值自动增长(整数类型,而且为主键) DEFAULT 为该字段设置默认值 UNSIGNED 无符号 ZEROFILL 使用0填充 示例: mysql> desc t6; +-------+---------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +-------+---------+------+-----+---------+-------+ | id | int(11) | YES | | NULL | | +-------+---------+------+-----+---------+-------+ 字段名 数据类型 是否为空 主键 默认值 其他
说明:
1、 是否允许为空,默认NULL,可设置NOT NULL,字段不允许为空,必须赋值 2、 字段是否有默认值,缺省的默认值是NULL,如果插入记录时不给字段赋值,此字段使用默认值 sex enum('male','female') not null default 'male' 3、 是否是key,主键 primary key,外键 foreign key,索引 (index,unique...)
2、not null与default
是否可以为空,nul表示空,非字符串:
not null:不可以为空
null:可以为空
多数情况下可能还需要用default设置插入的时候没有设置值的情况下,数据库应该填入的默认值,否则可能引起插入失败:
not null default ‘xxx’
#not null default mysql> create table t1(id int,name char(16),sex char(3) not null default '男'); Query OK, 0 rows affected (0.02 sec) mysql> insert into t1 (id,name) values (1,'Yim'); Query OK, 1 row affected (0.00 sec) mysql> select * from t1; +------+------+-----+ | id | name | sex | +------+------+-----+ | 1 | Yim | 男 | +------+------+-----+ 1 row in set (0.00 sec)
3、unique
设置唯一约束unique
方法一:在某一个字段后用unique mysql> create table t2(id int,name char(16) unique); Query OK, 0 rows affected (0.02 sec) mysql> insert into t2 values(1,'Yim'); Query OK, 1 row affected (0.00 sec) mysql> insert into t2 values(1,'Yim'); ERROR 1062 (23000): Duplicate entry 'Yim' for key 'name' #name重复,报错 方法二:在所有字段后单独定义unique mysql> create table t3(id int,name char(16),unique(name)); Query OK, 0 rows affected (0.04 sec) mysql> insert into t3 values(1,'Yim'); Query OK, 1 row affected (0.00 sec) mysql> insert into t3 values(1,'Yim'); ERROR 1062 (23000): Duplicate entry 'Yim' for key 'name' #联合唯一 mysql> create table service(id int primary key auto_increment,ip char(10),port int,unique(ip,port)); Query OK, 0 rows affected (0.02 sec) mysql> insert into service(ip,port) values ('1.1.1.1',3306); Query OK, 1 row affected (0.00 sec) mysql> insert into service(ip,port) values ('1.1.1.1',3306); ERROR 1062 (23000): Duplicate entry '1.1.1.1-3306' for key 'ip'
4、primary key
primary key字段的值不为空且唯一,就是not null unique
一个表中:单列做主键、多列做主键(复合主键),但一个表只能有一个主键
##############单列主键################## 方法一:not null+unique mysql> create table t4(id int not null unique,name char(16)); Query OK, 0 rows affected (0.02 sec) mysql> desc t4; +-------+----------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +-------+----------+------+-----+---------+-------+ | id | int(11) | NO | PRI | NULL | | | name | char(16) | YES | | NULL | | +-------+----------+------+-----+---------+-------+ 2 rows in set (0.00 sec) 方法二:在某一个字段后用primary key mysql> create table t5(id int primary key,name char(16)); Query OK, 0 rows affected (0.02 sec) mysql> desc t5; +-------+----------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +-------+----------+------+-----+---------+-------+ | id | int(11) | NO | PRI | NULL | | | name | char(16) | YES | | NULL | | +-------+----------+------+-----+---------+-------+ 2 rows in set (0.00 sec) 方法三:在所有字段后单独定义primary key mysql> create table t6(id int,name char(16),primary key(id)); Query OK, 0 rows affected (0.02 sec) mysql> desc t6; +-------+----------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +-------+----------+------+-----+---------+-------+ | id | int(11) | NO | PRI | 0 | | | name | char(16) | YES | | NULL | | +-------+----------+------+-----+---------+-------+ 2 rows in set (0.00 sec) ###############多列主键############### mysql> create table t8(id int,name char(16),primary key(id,name)); Query OK, 0 rows affected (0.02 sec) mysql> desc t8; +-------+----------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +-------+----------+------+-----+---------+-------+ | id | int(11) | NO | PRI | 0 | | | name | char(16) | NO | PRI | | | +-------+----------+------+-----+---------+-------+ 2 rows in set (0.00 sec)
5、auto_increment
约束字段为自动增长,被约束的字段必须同时被key约束
#不指定id,则自动增长 mysql> create table t9(id int primary key auto_increment,name char(16)); Query OK, 0 rows affected (0.02 sec) mysql> desc t9; +-------+----------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +-------+----------+------+-----+---------+----------------+ | id | int(11) | NO | PRI | NULL | auto_increment | | name | char(16) | YES | | NULL | | +-------+----------+------+-----+---------+----------------+ 2 rows in set (0.00 sec) mysql> insert into t9 (name) values ('Yim'),('Jim'); Query OK, 2 rows affected (0.00 sec) Records: 2 Duplicates: 0 Warnings: 0 mysql> select * from t9; +----+------+ | id | name | +----+------+ | 1 | Yim | | 2 | Jim | +----+------+ 2 rows in set (0.00 sec) #也可指定id mysql> insert into t9 values(5,'xiaoming'); Query OK, 1 row affected (0.00 sec) mysql> insert into t9 values(7,'xiaohong'); Query OK, 1 row affected (0.00 sec) mysql> select * from t9; +----+----------+ | id | name | +----+----------+ | 1 | Yim | | 2 | Jim | | 5 | xiaoming | | 7 | xiaohong | +----+----------+ 4 rows in set (0.00 sec)
MySQL字段自增长AUTO_INCREMENT:
#修改自增的初始值 1、创建表时指定AUTO_INCREMENT自增值的初始值(即起始值): CREATE TABLE XXX (ID INT(5) PRIMARY KEY AUTO_INCREMENT) AUTO_INCREMENT=100; 2、通过 ALTER TABLE 修改初始值(但是要大于表中的 AUTO_INCREMENT 自增值,否则设置无效): ALTER TABLE XXX AUTO_INCREMENT=100; #设置步长 1、 基于会话级别 set session auth_increment_increment=2 #修改会话级别的步长 2、基于全局级别的 set global auth_increment_increment=2 #修改全局级别的步长(所有会话都生效)
6、foreign key
1)理解foreign key
员工信息表有三个字段:工号 姓名 部门
公司有2个部门,但是有1万个员工,那意味着部门这个字段需要重复存储,部门名字越长,越浪费
解决方法:定义一个部门表,然后让员工关联该表(一对多)
#先建立被关联的部门表(被关联的字段,即references指定的另外一个表的字段,必须保证唯一) create table dep(id int primary key auto_increment,name char(64)); #再建立员工表 create table emp(id int primary key auto_increment,name char(32),age int,dep_id int,foreign key(dep_id) references dep(id) on delete cascade on update cascade); #dep_id外键,关联父表dep主键id,级联删除,级联更新 #先插入部门信息 insert into dep(name) values('IT'),('HR'); #再插入员工信息 insert into emp(name,age,dep_id) values('Yim',25,1),('Jim',25,1),('Jerry',30,2); #删除IT部门(id=1) delete from dep where id=1; #IT部门下的员工也被删除 mysql> select * from emp; +----+-------+------+--------+ | id | name | age | dep_id | +----+-------+------+--------+ | 3 | Jerry | 30 | 2 | +----+-------+------+--------+ 1 row in set (0.00 sec)
2)如何找出两张表之间的关系:
分析步骤: #1、先站在左表的角度去找 是否左表的多条记录可以对应右表的一条记录,如果是,则证明左表的一个字段foreign key 右表一个字段(通常是id) #2、再站在右表的角度去找 是否右表的多条记录可以对应左表的一条记录,如果是,则证明右表的一个字段foreign key 左表一个字段(通常是id) #3、总结: #多对一: 如果只有步骤1成立,则是左表多对一右表 如果只有步骤2成立,则是右表多对一左表 #多对多 如果步骤1和2同时成立,则证明这两张表时一个双向的多对一,即多对多,需要定义一个这两张表的关系表来专门存放二者的关系 #一对一: 如果1和2都不成立,而是左表的一条记录唯一对应右表的一条记录,反之亦然。这种情况很简单,就是在左表foreign key右表的基础上,将左表的外键字段设置成unique即可
多对多的例子:
#多对多 create table book( id int primary key auto_increment, name char(32), type char(64) ); create table author( id int primary key auto_increment, name char(32) ); create table author2book( id int primary key auto_increment, book_id int, author_id int, foreign key(book_id) references book(id) on delete cascade on update cascade, foreign key(author_id) references author(id) on delete cascade on update cascade );
一对一的例子:
#两张表:学生表和客户表 #一对一:一个学生是一个客户,一个客户有可能变成一个学生,即一对一的关系 #一定是student来foreign key表customer,这样就保证了:学生一定是一个客户;客户不一定是学生,但有可能成为一个学生 #关联方式:foreign key+unique 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 );
1.11 数据操作
1、插入数据
#插入完整数据(顺序插入) 方法一:insert into表名(字段1,字段2,字段3…字段n) values(值1,值2,值3…值n); insert into t19(id,name) values(1,'Yim'); 方法二:insert into 表名 values (值1,值2,值3…值n); insert into t19 values (2,'Jim'); #指定字段插入数据 inser into 表名(字段1,字段2,字段3…) values (值1,值2,值3…); insert into t19 (name,id) values ('xiaoming',3),('xiaohong',4); #插入多条记录 insert into 表名 values (值1,值2,值3…值n),(值1,值2,值3…值n); insert into t19 values (5,'zhangsan'),(6,'lisi'); #插入查询结果 insert into 表名(字段1,字段2…) select 字段1,字段2… from 表2 where …; insert into t19(id,name) select id,name from t1;
2、更新数据
#更新数据 update 表名 set 字段1=值1,字段2=值2 where condition; 示例: update t1 set name='xiaohong',sex='女' where id=1; update mysql.user set password=password('123') where user='root' and host='127.0.0.1';
3、删除数据
#删除数据 delete from 表名 where condition; 示例: delete from t19 where id=1; delete from mysql.user where not user='root';
4、单表查询
#语法: select distinct字段1,字段2… from表名 #distinct对查询结果进行去重 where 条件 #分组之前过滤 group by 分组字段 having 过滤条件 #分组之后过滤 order by 排序字段 limit 显示条数 #执行优先级 from:找到表 where:根据where指定的约束条件,去表中去出一条条记录 group by:将取出的记录进行分组,如果没有group by则整体作为一组 having:将分组的结果进行having过滤 select:执行select distinct:去重 order by:将结果按条件排序 limit:限制结果的显示条数
简单查询:
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, 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 | | 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(name,sex,age,hire_date,post,salary,office,depart_id) values ('Yim','male',25,'20170301','teacher',7300.33,201,1), #以下是教学部 ('Jim','male',78,'20150302','teacher',1000000.31,201,1), ('Aaron','male',81,'20130305','teacher',8300,201,1), ('Geoffrey','male',73,'20140701','teacher',3500,201,1), ('Hugo','male',28,'20121101','teacher',2100,201,1), ('jonas','female',18,'20110211','teacher',9000,201,1), ('Leo','male',18,'19000301','teacher',30000,201,1), ('Mandel','male',48,'20101111','teacher',10000,201,1), ('潇潇 ','female',48,'20150311','sale',3000.13,301,2),#以下是销售部门 ('可可','female',38,'20101101','sale',2000.35, 301,2), ('东东','female',18,'20110312','sale',1000.37, 301,2), ('云云','female',18,'20160513','sale',3000.29,301,2), ('卡卡','female',28,'20170127','sale',4000.33,301,2), ('洪七公','male',28,'20160311','operation',10000.13,303,3), #以下是运营部门 ('黄药师','male',18,'19970312','operation',20000,303,3), ('欧阳锋','female',18,'20130311','operation',19000,303,3), ('周伯通','male',18,'20150411','operation',18000,303,3), ('杨康','female',18,'20140512','operation',17000,303,3) ; #简单查询 select * from employee; select id,name employee; #通过四则运算查询 select name,salary*12 from employee; #名字和年薪 select name as 姓名,salary*12 as 年薪 from employee; #别名 #去重 select distinct post from employee; #去重,显示有哪些职位 #定义显示格式 select concat('姓名:',name,'年薪',salary*12) from employee; #concat函数用于连接字符串 select concat_ws(':',name,salary*12) from employee; #concat_ws函数第一个参数为分隔符
约束条件:
where字句中可以使用:
1、比较运算符:>、<、>=、 <= 、<>、!=
2、between 80 and 100 #大于等于80,小于等于100
3、in(80,90,100) #是否有某些值
4、like ‘cache%’ #pattern可以是%或_,%表示任意多个字符,_表示一个字符
5、逻辑运算符:在多个条件直接可以使用逻辑运算符and、or、not
#单条件查询 select name from employee where post='teacher'; #多条件查询 select name from employee where post='teacher' and salary>10000; #关键字between and select name from employee where post='teacher' and salary between 8000 and 10000; select name from employee where post='teacher' and salary not between 8000 and 10000; #关键字in集合查询 select name from employee where salary=10000 or salary=20000; select name from employee where salary in(10000,20000); select name from employee where salary not in(10000,20000); #关键字like模糊查询 select name from employee where name like '%im'; select name from employee where name like '__'; select name from employee where name like '杨_'; #关键字is null(判断某个字段是否为NULL不能用=号,需要用is) select name,post_comment from employee where post_comment is null; select name,post_comment from employee where post_comment is not null;
分组查询GROUP BY: ·
分组是在where之后,即分组是基于where之后得到的记录而进行的
分组指的是:将所有记录按照某个相同字段进行归类,比如针对员工信息表的职位分组,或者按照性别进行分组等
前提:可以按照任意字段分组,但是分组完毕后,比如group by post,只能查看post字段,如果想看组内信息,需要借助于聚合函数
聚合函数有:max、min、avg、sum、count
#接上面的例子 #岗位名以及各岗位的最高薪资 mysql> select post,max(salary) from employee group by post; +-----------+-------------+ | post | max(salary) | +-----------+-------------+ | operation | 20000.00 | | sale | 4000.33 | | teacher | 1000000.31 | +-----------+-------------+ 3 rows in set (0.00 sec) #岗位名以及各岗位的最低薪资 mysql> select post,min(salary) from employee group by post; +-----------+-------------+ | post | min(salary) | +-----------+-------------+ | operation | 10000.13 | | sale | 1000.37 | | teacher | 2100.00 | +-----------+-------------+ 3 rows in set (0.00 sec) #岗位名以及各岗位的平均薪资 mysql> select post,avg(salary) from employee group by post; +-----------+---------------+ | post | avg(salary) | +-----------+---------------+ | operation | 16800.026000 | | sale | 2600.294000 | | teacher | 133775.080000 | +-----------+---------------+ 3 rows in set (0.00 sec) #岗位名以及各岗位的总共薪资 mysql> select post,sum(salary) from employee group by post; +-----------+-------------+ | post | sum(salary) | +-----------+-------------+ | operation | 84000.13 | | sale | 13001.47 | | teacher | 1070200.64 | +-----------+-------------+ 3 rows in set (0.00 sec) #岗位名以及各岗位内包含的员工个数 mysql> select post,count(id) from employee group by post; +-----------+-----------+ | post | count(id) | +-----------+-----------+ | operation | 5 | | sale | 5 | | teacher | 8 | +-----------+-----------+ 3 rows in set (0.00 sec) #公司内男员工和女员工的个数 mysql> select sex,count(id) from employee group by sex; +--------+-----------+ | sex | count(id) | +--------+-----------+ | male | 10 | | female | 8 | +--------+-----------+ 2 rows in set (0.00 sec) #岗位名以及岗位包含的所有员工名字 mysql> select post,group_concat(name) from employee group by post; #GROUP_CONCAT函数返回一个字符串结果,该结果由分组中的值连接组合而成 +-----------+------------------------------------------------+ | post | group_concat(name) | +-----------+------------------------------------------------+ | operation | 杨康,周伯通,欧阳锋,黄药师,洪七公 | | sale | 卡卡,云云,东东,可可,潇潇 | | teacher | Mandel,Leo,jonas,Hugo,Geoffrey,Aaron,Jim,Yim | +-----------+------------------------------------------------+ 3 rows in set (0.00 sec) #男员工的平均薪资,女员工的平均薪资 mysql> select sex,avg(salary) from employee group by sex; +--------+---------------+ | sex | avg(salary) | +--------+---------------+ | male | 110920.077000 | | female | 7250.183750 | +--------+---------------+ 2 rows in set (0.00 sec)
HAVING过滤:
having与where不同点:
where发生在分组group by之前,因而where中可以有任何字段,但是不能使用聚合函数
having发生在分组group by之后,因而having中可以使用分组的字段,但无法直接取到其他字段,可以使用聚合函数
#where和group by,找出年龄20以上,每个部门里的最高工资 mysql> select post,max(salary) from employee where age>20 group by post; +-----------+-------------+ | post | max(salary) | +-----------+-------------+ | operation | 10000.13 | | sale | 4000.33 | | teacher | 1000000.31 | +-----------+-------------+ 3 rows in set (0.00 sec) #最高工资(不分组,默认整体是一组) mysql> select max(salary) from employee; +-------------+ | max(salary) | +-------------+ | 1000000.31 | +-------------+ 1 row in set (0.00 sec) #岗位平均薪资大于10000的岗位名、平均工资 mysql> select post,avg(salary) from employee group by post having avg(salary)>10000; +-----------+---------------+ | post | avg(salary) | +-----------+---------------+ | operation | 16800.026000 | | teacher | 133775.080000 | +-----------+---------------+ 2 rows in set (0.00 sec) #岗位内包含的员工个数大于5的岗位名、岗位内包含员工名字、个数 mysql> select post,group_concat(name),count(id) from employee group by post having count(id)>5; +---------+----------------------------------------------+-----------+ | post | group_concat(name) | count(id) | +---------+----------------------------------------------+-----------+ | teacher | Mandel,Leo,jonas,Hugo,Geoffrey,Aaron,Jim,Yim | 8 | +---------+----------------------------------------------+-----------+ 1 row in set (0.00 sec) #岗位平均薪资大于10000且小于20000的岗位名、平均工资 mysql> select post,avg(salary) from employee group by post having avg(salary) > 10000 and avg(salary) <20000; +-----------+--------------+ | post | avg(salary) | +-----------+--------------+ | operation | 16800.026000 | +-----------+--------------+ 1 row in set (0.00 sec
查询排序:ORDER BY
单列排序: select * from employee order by salary; select * from employee order by salary asc; select * from employee order by salary desc; 多列排序:先按照age排序,如果年纪相同,则按照薪资排序 select * from employee order by age,salary desc; #查询所有员工信息,先按照age升序排序,如果age相同则按照hire_date降序排序 mysql> select * from employee order by age asc,hire_date desc; #查询各岗位平均薪资大于10000的岗位名、平均工资,结果按平均薪资升序排列 mysql> select post,avg(salary) from employee group by post having avg(salary)>10000 order by avg(salary) asc; +-----------+---------------+ | post | avg(salary) | +-----------+---------------+ | operation | 16800.026000 | | teacher | 133775.080000 | +-----------+---------------+ 2 rows in set (0.00 sec) #查询各岗位平均薪资大于10000的岗位名、平均工资,结果按平均薪资降序排列 mysql> select post,avg(salary) from employee group by post having avg(salary)>10000 order by avg(salary) desc; +-----------+---------------+ | post | avg(salary) | +-----------+---------------+ | teacher | 133775.080000 | | operation | 16800.026000 | +-----------+---------------+ 2 rows in set (0.00 sec)
限制查询的记录数:LIMIT
select * from employee order by salary desc limit 3; #默认初始位置为0 select * from employee order by salary desc limit 0,5; #从第0开始,即先查询出第一条,然后包含这一条在内往后查5条
正则表达式查询
mysql> select * from employee where name regexp '^Y'; mysql> select * from employee where name regexp 'im$'; mysql> select * from employee where name regexp 'm{2}'; #查看所有员工中名字是jin开头,n或者g结尾果的员工信息 mysql> select * from employee where name regexp '^jin.*[gn]$';
5、多表查询
#准备表 create table dep(id int,name varchar(20)); create table emp(id int primary key auto_increment,name varchar(20),sex enum('male','female') not null default 'male',age int,dep_id int); #插入数据 insert into dep values(200,'技术'),(201,'人力资源'),(202,'销售'),(203,'运营'); insert into emp(name,sex,age,dep_id) values ('Yim','male',25,200); insert into emp(name,sex,age,dep_id) values ('Yim','male',18,200), ('可可','female',48,201), ('东东','male',38,201), ('张三','female',28,202), ('Jim','male',18,200), ('欧阳锋','female',18,204) ; #查看表结构和数据 mysql> desc dep; +-------+-------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +-------+-------------+------+-----+---------+-------+ | id | int(11) | YES | | NULL | | | name | varchar(20) | YES | | NULL | | +-------+-------------+------+-----+---------+-------+ 2 rows in set (0.00 sec) mysql> desc emp; +--------+-----------------------+------+-----+---------+----------------+ | 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 | | +--------+-----------------------+------+-----+---------+----------------+ 5 rows in set (0.00 sec) mysql> select * from dep; +------+--------------+ | id | name | +------+--------------+ | 200 | 技术 | | 201 | 人力资源 | | 202 | 销售 | | 203 | 运营 | +------+--------------+ 4 rows in set (0.00 sec) mysql> select * from emp; +----+-----------+--------+------+--------+ | id | name | sex | age | dep_id | +----+-----------+--------+------+--------+ | 1 | Yim | male | 18 | 200 | | 2 | 可可 | female | 48 | 201 | | 3 | 东东 | male | 38 | 201 | | 4 | 张三 | female | 28 | 202 | | 5 | Jim | male | 18 | 200 | | 6 | 欧阳锋 | female | 18 | 204 | +----+-----------+--------+------+--------+ 6 rows in set (0.00 sec)
多表链接查询:
外链接语法:
select 字段列表 from 表1 inner|left|right join 表2 on 表1.字段=表2.字段;
注:
inner|left|right join,分别表示内链接,左链接,右链接
表1.字段 = 表2.字段,是链接条件
1) 交叉链接,不适用任何匹配条件。生成笛卡尔乘积 mysql> select * from dep,emp; +------+--------------+----+-----------+--------+------+--------+ | id | name | id | name | sex | age | dep_id | +------+--------------+----+-----------+--------+------+--------+ | 200 | 技术 | 1 | Yim | male | 18 | 200 | | 201 | 人力资源 | 1 | Yim | male | 18 | 200 | | 202 | 销售 | 1 | Yim | male | 18 | 200 | | 203 | 运营 | 1 | Yim | male | 18 | 200 | | 200 | 技术 | 2 | 可可 | female | 48 | 201 | | 201 | 人力资源 | 2 | 可可 | female | 48 | 201 | | 202 | 销售 | 2 | 可可 | female | 48 | 201 | | 203 | 运营 | 2 | 可可 | female | 48 | 201 | | 200 | 技术 | 3 | 东东 | male | 38 | 201 | | 201 | 人力资源 | 3 | 东东 | male | 38 | 201 | | 202 | 销售 | 3 | 东东 | male | 38 | 201 | | 203 | 运营 | 3 | 东东 | male | 38 | 201 | | 200 | 技术 | 4 | 张三 | female | 28 | 202 | | 201 | 人力资源 | 4 | 张三 | female | 28 | 202 | | 202 | 销售 | 4 | 张三 | female | 28 | 202 | | 203 | 运营 | 4 | 张三 | female | 28 | 202 | | 200 | 技术 | 5 | Jim | male | 18 | 200 | | 201 | 人力资源 | 5 | Jim | male | 18 | 200 | | 202 | 销售 | 5 | Jim | male | 18 | 200 | | 203 | 运营 | 5 | Jim | male | 18 | 200 | | 200 | 技术 | 6 | 欧阳锋 | female | 18 | 204 | | 201 | 人力资源 | 6 | 欧阳锋 | female | 18 | 204 | | 202 | 销售 | 6 | 欧阳锋 | female | 18 | 204 | | 203 | 运营 | 6 | 欧阳锋 | female | 18 | 204 | +------+--------------+----+-----------+--------+------+--------+ 2)内链接:只连接匹配的行 #找两张表共有的部分,相当于利用条件从笛卡尔乘积中筛选出正确的结果 #dep表中没有204这个部门,因而emp表中关于204这条员工信息没有匹配出来 mysql> select * from dep inner join emp on dep.id=emp.dep_id; +------+--------------+----+--------+--------+------+--------+ | id | name | id | name | sex | age | dep_id | +------+--------------+----+--------+--------+------+--------+ | 200 | 技术 | 1 | Yim | male | 18 | 200 | | 201 | 人力资源 | 2 | 可可 | female | 48 | 201 | | 201 | 人力资源 | 3 | 东东 | male | 38 | 201 | | 202 | 销售 | 4 | 张三 | female | 28 | 202 | | 200 | 技术 | 5 | Jim | male | 18 | 200 | +------+--------------+----+--------+--------+------+--------+ 5 rows in set (0.00 sec) #上述sql等同于 mysql> select * from dep,emp where dep.id=emp.dep_id; 3)左链接:优先显示左表全部记录 #以左表为准,找出所有部门信息,当然也包括没有员工的部门 #本质就是:在内链接的基础上增加左边有右边没有的结果 mysql> select * from dep left join emp on dep.id=emp.dep_id; +------+--------------+------+--------+--------+------+--------+ | id | name | id | name | sex | age | dep_id | +------+--------------+------+--------+--------+------+--------+ | 200 | 技术 | 1 | Yim | male | 18 | 200 | | 201 | 人力资源 | 2 | 可可 | female | 48 | 201 | | 201 | 人力资源 | 3 | 东东 | male | 38 | 201 | | 202 | 销售 | 4 | 张三 | female | 28 | 202 | | 200 | 技术 | 5 | Jim | male | 18 | 200 | | 203 | 运营 | NULL | NULL | NULL | NULL | NULL | +------+--------------+------+--------+--------+------+--------+ 6 rows in set (0.00 sec) 4)右链接:优先显示右表全部记录 #以右表为准,找出所有员工信息,当然也包括没有部门的员工 #本质就是:在内连接的基础上增加右边有左边没有的结果 mysql> select * from dep right join emp on dep.id=emp.dep_id; +------+--------------+----+-----------+--------+------+--------+ | id | name | id | name | sex | age | dep_id | +------+--------------+----+-----------+--------+------+--------+ | 200 | 技术 | 1 | Yim | male | 18 | 200 | | 200 | 技术 | 5 | Jim | male | 18 | 200 | | 201 | 人力资源 | 2 | 可可 | female | 48 | 201 | | 201 | 人力资源 | 3 | 东东 | male | 38 | 201 | | 202 | 销售 | 4 | 张三 | female | 28 | 202 | | NULL | NULL | 6 | 欧阳锋 | female | 18 | 204 | +------+--------------+----+-----------+--------+------+--------+ 6 rows in set (0.00 sec) 5)全外链接:显示左右两个表全部记录 #在内连接的基础上增加左边有右边没有的和右边有左边没有的结果 #注意:mysql不支持全外链接full join,但可以使用下面的方法实现 mysql> select * from dep left join emp on dep.id=emp.dep_id union select * from dep right join emp on dep.id=emp.dep_id; +------+--------------+------+-----------+--------+------+--------+ | id | name | id | name | sex | age | dep_id | +------+--------------+------+-----------+--------+------+--------+ | 200 | 技术 | 1 | Yim | male | 18 | 200 | | 201 | 人力资源 | 2 | 可可 | female | 48 | 201 | | 201 | 人力资源 | 3 | 东东 | male | 38 | 201 | | 202 | 销售 | 4 | 张三 | female | 28 | 202 | | 200 | 技术 | 5 | Jim | male | 18 | 200 | | 203 | 运营 | NULL | NULL | NULL | NULL | NULL | | NULL | NULL | 6 | 欧阳锋 | female | 18 | 204 | +------+--------------+------+-----------+--------+------+--------+ 7 rows in set (0.00 sec)
符合条件链接查询
示例1:以内链接的方式,找出年龄大于25岁的员工以及员工所在的部门 mysql> select emp.name,dep.name,emp.age from dep inner join emp on dep.id=emp.dep_id where age>25; +--------+--------------+------+ | name | name | age | +--------+--------------+------+ | 可可 | 人力资源 | 48 | | 东东 | 人力资源 | 38 | | 张三 | 销售 | 28 | +--------+--------------+------+ 3 rows in set (0.00 sec) 示例2:以内链接的方式,以age字段的升序方式显示 mysql> select emp.name,dep.name,emp.age from dep inner join emp on dep.id=emp.dep_id where age>25 order by age asc; +--------+--------------+------+ | name | name | age | +--------+--------------+------+ | 张三 | 销售 | 28 | | 东东 | 人力资源 | 38 | | 可可 | 人力资源 | 48 | +--------+--------------+------+ 3 rows in set (0.00 sec)
子查询:
子查询是将一个查询语句嵌套在另一个查询语句中
内层查询语句的查询结果,可以为外层查询语句提供查询条件
子查询中可以包含:in、not in、any、all、exists和not exists等关键字
还可以包含比较运算符:=、!=、>、<等
1) 带in关键字的子查询 #查询平均年龄在25岁以上的部门名 mysql> select name from dep where id in(select dep_id from emp group by dep_id having avg(age)>25); +--------------+ | name | +--------------+ | 人力资源 | | 销售 | +--------------+ 2 rows in set (0.00 sec) #查看技术部员工姓名 mysql> select name from emp where dep_id in(select id from dep where name='技术'); +------+ | name | +------+ | Yim | | Jim | +------+ 2 rows in set (0.00 sec) #查看<=1人的部门 mysql> select name from dep where id in(select dep_id from emp group by dep_id having count(id)<=1); +--------+ | name | +--------+ | 销售 | +--------+ 1 row in set (0.00 sec) 2) 带比较运算符的子查询 #查询大于所有人平均年龄的员工名与年龄 mysql> select name,age from emp where age>(select avg(age) from emp); +--------+------+ | name | age | +--------+------+ | 可可 | 48 | | 东东 | 38 | +--------+------+ 2 rows in set (0.00 sec) #查询大于部门内平均年龄的员工名、年龄 mysql> select name,age from emp inner join (select dep_id,avg(age) as age_avg from emp group by dep_id) as t2 on emp.dep_id=t2.dep_id where emp.age > t2.age_avg; +--------+------+ | name | age | +--------+------+ | 可可 | 48 | +--------+------+ 1 row in set (0.00 sec) 3) 带exists关键字的子查询 #exists关键字表示存在,在使用exists关键字时,内层查询语句不返回查询的记录,而是返回一个真假值True或False #当返回True时,外层查询语句将进行查询;当返回False时,外层查询语句不进行查询 mysql> select * from dep where exists(select * from dep where name='技术'); +------+--------------+ | id | name | +------+--------------+ | 200 | 技术 | | 201 | 人力资源 | | 202 | 销售 | | 203 | 运营 | +------+--------------+ 4 rows in set (0.00 sec) mysql> select * from dep where exists(select * from dep where name='行政'); Empty set (0.00 sec)
拓展:
查询每个部门最新入职的那位员工
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, name varchar(20) not null, sex enum('male','female') not null default 'male', #大部分是男的 age int(3) unsigned not null default 28, hire_date date not null, post varchar(50), post_comment varchar(100), salary double(15,2), office int, #一个部门一个屋子 depart_id int ); #插入记录 #三个部门:教学、销售、运营 insert into employee(name,sex,age,hire_date,post,salary,office,depart_id) values ('Yim','male',25,'20170301','teacher',7300.33,201,1), #以下是教学部 ('Jim','male',78,'20150302','teacher',1000000.31,201,1), ('Aaron','male',81,'20130305','teacher',8300,201,1), ('Geoffrey','male',73,'20140701','teacher',3500,201,1), ('Hugo','male',28,'20121101','teacher',2100,201,1), ('jonas','female',18,'20110211','teacher',9000,201,1), ('Leo','male',18,'19000301','teacher',30000,201,1), ('Mandel','male',48,'20101111','teacher',10000,201,1), ('潇潇 ','female',48,'20150311','sale',3000.13,301,2),#以下是销售部门 ('可可','female',38,'20101101','sale',2000.35, 301,2), ('东东','female',18,'20110312','sale',1000.37, 301,2), ('云云','female',18,'20160513','sale',3000.29,301,2), ('卡卡','female',28,'20170127','sale',4000.33,301,2), ('洪七公','male',28,'20160311','operation',10000.13,303,3), #以下是运营部门 ('黄药师','male',18,'19970312','operation',20000,303,3), ('欧阳锋','female',18,'20130311','operation',19000,303,3), ('周伯通','male',18,'20150411','operation',18000,303,3), ('杨康','female',18,'20140512','operation',17000,303,3) ; mysql> select t1.name,t1.hire_date,t2.* 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; +-----------+------------+-----------+------------+ | name | hire_date | post | max_date | +-----------+------------+-----------+------------+ | Yim | 2017-03-01 | teacher | 2017-03-01 | | 卡卡 | 2017-01-27 | sale | 2017-01-27 | | 洪七公 | 2016-03-11 | operation | 2016-03-11 | +-----------+------------+-----------+------------+ 3 rows in set (0.00 sec)