4.mysql 基础
一.数据库基本
1. 数据库概念
数据库: 存储数据的仓库
数据库类型:层次式数据库(存储的方便,查询很慢), 网络式数据库(查询很快,存储不方便), 关系型数据库(以行和列的形式存储数据)
2.关系型数据库
常见的数据库 商业数据库:Oracle 、SQLServer、DB2、Sybase
开源数据库: MySql、SQLLite
3.MySQL数据库服务器、数据库和表的关系
所谓安装数据库服务器,只是在机器上装了一个数据库管理程序,这个管理程序可以管理多个数据库,一般开发人员会针对每一个应用创建一个数据库。
为保存应用中实体的数据,一般会在数据库创建多个表,以保存程序中实体的数据。
数据库服务器、数据库和表的关系如图所示:
数据在数据库中的存储方式
4.SQL语言
Structured Query Language, 结构化查询语言
非过程性语言(就是上一句语句与下一个语句没有关系)
美国国家标准局(ANSI)与国际标准化组织(ISO)已经制定了SQL标准
为加强SQL的语言能力,各厂商增强了过程性语言的特征
- 如Oracle的PL/SQL 过程性处理能力
- SQL Server、Sybase的T-SQL
- SQL是用来存取关系数据库的语言,具有查询、操纵、定义和控制关系型数据库的四方面功能。
二.Sql语句-----库操作
1.创建数据库
CREATE DATABASE [IF NOT EXISTS] db_name [create_specification[,create_specification] ...] create_specification: 7 [DEFAULT] CHARACTER SET charset_name | [DEFAULT] COLLATE collation_name
CHARACTER SET:指定数据库采用的字符集
COLLATE:指定数据库字符集的比较方式
查看mysql存储位置 :show global variables like "%datadir%"; z
这个可以查看到mysql 存放数据库的文件 可以查看此数据库的一些配置
例子
创建一个名称为mydb1的数据库。
create database mydb1;
创建一个使用utf8字符集的mydb2数据库。
create database mydb2 character set gbk;
创建一个使用utf8字符集,并带校对规则的mydb3数据库。
create database mydb3 character set utf8 collate utf8_bin
2.查看、删除数据库
显示数据库语句 |
SHOW DATABASES |
显示数据库创建语句 |
SHOW CREATE DATABASE db_name |
数据库删除语句 | DROP DATABASE [IF EXISTS] db_name |
3.修改数据库
ALTER DATABASE [IF NOT EXISTS] db_name
[alter_specification [, alter_specification] ...] alter_specification:
[DEFAULT] CHARACTER SET charset_name | [DEFAULT] COLLATE collation_name
例子:
查看服务器中的数据库,并把其中某一个数据库的字符集修改为 gbk;
alter database mydb3 character set gbk;
4.选择数据库
using db_name;
查看当前使用的数据库
select database();
三.表操作
1.创建表
CREATE TABLE table_name ( field1 datatype, field2 datatype, field3 datatype )
[character set 字符集][collate 校对规则
character set 字符集 collate 校对规则 field:指定列名 datatype:指定列类型 注意:创建表时,要根据需保存的数据创建相应的列,并根据数据的类型定义相应的列类 型。
例子:
create table user( id int, name char(10), password varchar(20), birthday date );
2.3 创建表employee create table employee( id int, name varchar(10), gender varchar(2), birthday date, entry_date date, job varchar(20), salary double, resume text );
查看表结构:
desc employee;
查看所有表:show tables
2.MySQL常用数据类型
varchar存储数据时只占用数据本身长度,不会将全部字段长度占用。 varchar读取数据时,先判断数据长度,再根据长度读取,速度相对char较慢。 VARCHAR(20)
char存储数据时,不论数据本身有多长,都会占用字段全部长度。 char在读取时读取固定长度,速度相对varchar较快 CHAR(20)
字符串型 ○
BLOB(流数据 多用于存放图片但是已经不常用,可以直接存放图片路径就好)、TEXT (存放4mb文本数据,也不常用了,可以直接赋予链接路径)大数据类型 ○
TINYINT (相当于byte)、SMALLINT (相当于short)、INT、BIGINT、FLOAT、DOUBLE 数值型。
BIT 逻辑型。只有0 1 但是不常用了,对数据库的一些结构方面没好处
DATE、TIME、DATETIME、TIMESTAMP 日期型。
3.定义单表字段的约束
- 定义主键约束
- primary key:不允许为空,不允许重复
- 删除主键:alter table tablename drop primary key ;
- 主键自动增长 :auto_increment
-
一个表格一般情况下都会设置一个主键,表格中存储主键可以提交查询效率。
一个字段如果被auto_increment 修饰,则这个字段一定是主键字段。
主键字段可以设置为auto_increment也可以不设置。 - 定义唯一约束
- unique
- 例如:name varchar(20) unique
- 定义非空约束
- not null
- 例如:salary double not null
- 外键约束
1. 查看表信息
查看表结构:desc tabname;
查看当前所有表: show tables;
查看当前数据库表建表语句:show create table tabName;
2.修改表
使用 ALTER TABLE 语句追加, 修改, 或删除列的语法
ALTER TABLE table ADD column datatype [DEFAULT expr] [, column datatype]..; ALTER TABLE table MODIFY column datatype [DEFAULT expr] [, column datatype]...; ALTER TABLE table DROP column;
alter table table_name add column_name dataType; alter table table_name modify column_name dataType; alter table table_name drop column_name;
修改表的名称:
rename table 表名 to 新表名;
rename table table_name to new_table_name;
修改表的字符集:
alter table user character set utf8;
修改列的名称:
ALTER TABLE table change old_column new_column typefiled;
- o 练习
在上面员工表的基本上增加一个image列。 alter table employee add image blob; 修改job列,使其长度为60。 alter table employee modify job varchar(60); 删除gender列。 alter table employee drop gender; 表名改为user。 rename table employee to emp; 修改表的字符集为utf8 alter table emp character set gbk; 列名name修改为username alter table emp change name username varchar(20); alter table emp change username username varchar(10);
- 删除表 :drop table tabname;
四.表数据操作-CRUD
- Insert语句 (增加数据)
- Update语句 (更新数据)
- Delete语句 (删除数据)
- Select语句(查找数据)
数据库中读写比例大约为7:3
1.Insert 新增数据
a. 插入的数据应与字段的数据类型相同。
b. 数据的大小应在列的规定范围内,例如:不能将一个长度为80的字符串加入到长度为40的列中。
c. 在values中列出的数据位置必须与被加入的列的排列位置相对应。
d. 字符和日期型数据应包含在单引号中。
e. 插入空值:不指定或insert into table value(null)
f. 如果要插入所有字段可以省写列列表,直接按表中字段顺序写值列表
g. 如果有自增长列,那么这列可以不给值 即insert 的时候可以设置为null;
1 插入数据 2 基本语句: 3 insert into table_name values(id,name,age); 4 准备表格: 5 create table employee( 6 id int primary key auto_increment , 7 name varchar(20), 8 gender varchar(2) , 9 birthday date, 10 entry_date date, 11 job varchar(20), 12 salary double, 13 resume text 14 ); 15 插入语句: 16 insert into employee values(1,'cy','ma','1980-09-09','1981-09-09','eat',5000.0,'can eat'); 17 insert into employee values(166,'cy','ma','1980-09-09','1981-09-09','eat',5000.0,'can eat'); 18 19 insert into employee values(null,'ls','fe','1999-10-10','2002-02-02','drink',5000.0,'can drink'); 20 insert into employee values(null,'cy','fe','1966-10-10','2002-02-02','ccc',25000.0,'can ccc'); 21 insert into employee values(null,'pq','fe','1955-10-10','2002-02-02','ddd',15000.0,'can ddd'); 22 23 还可以指定字段名称后再插入数据: 24 insert into employee(id,name,gender,birthday,entry_date,job,salary,resumen) values(null,'ls','fe','1999-10-10','2002-02-02','drink',5000.0,'can drink'); 25 insert into employee(id,name) values(null,'pq'); 26 insert into employee(name,id) values('mxb',null);
2.update 更新数据
更新数据 |
UPDATE tbl_name SET col_name1=expr1 [, col_name2=expr2 ...] [WHERE where_definition] |
更新表中满足条件的数据。 基本语句: update table_name set column_name = value; update employee set salary = 10000; update employee set salary = 1000 where id = 1; update employee set salary = 1000,job ='ccc'; 更新语句可以添加where子句,where子句包含的是一个条件,满足条件的内容才会发生更新操作。 更新时,可以连续书写多个字段,多个字段直接用逗号隔开。
将所有员工薪水修改为5000元。 update employee set salary = 5000; 将姓名为'cy'的员工薪水修改为3000元。 update employee set salary = 3000 where name='cy'; 将姓名为'ls'的员工薪水修改为4000元,job改为ccc。 update employee set salary = 4000,job ='ccc' where name = 'ls'; 将'pq'的薪水在原有基础上增加1000元。 update employee set salary = salary +1000 where name='pq';
3.Delete 删除数据
|
delete from tbl_name [WHERE where_definition] |
如果不使用where子句,将删除表中所有数据。 Delete语句不能删除某一列的值(可使用update) update table_name set 字段名=''; 使用delete语句仅删除记录,不删除表本身。如要删除表,使用drop table语句。 drop table table_name; 同insert和update一样,从一个表中删除记录将引起其它表的参照完整性问题,在修改数据库数据时,头脑中应该始终不要忘记这个潜在的问题。
基本语句: delete from table_name;---删除整张表的数据。 delete from table_name where 条件.---删除满足条件的数据。 a. Delete语句练习 删除表中名称为’ls’的记录。 delete from employee where name='ls'; 删除表中所有记录。 delete from employee; truncate删除数据: 使用truncate删除表中记录。 truncate employee; ---直接将正张表删除,再重建表结构。 truncate删除时会将表删除,再重建表结构。这种方式对于单表来说,删除效率要高于delete from。 但是由于会摧毁表,所以面对多表操作时,表间关系可能不再存在。多表时不推荐使用truncate删除。
4.Select 语句
• Select语句(1)
基本select语句
select 指定查询哪些列的数据。
column指定列名。
*号代表查询所有列。
from指定查询哪张表。
DISTINCT可选,指显示结果时,是否剔除重复数据
select 指定查询哪些列的数据。
column指定列名。
*号代表查询所有列。
from指定查询哪张表。
DISTINCT可选,指显示结果时,是否剔除重复数据
查询满足条件的数据。 基本语句: select * from table_name; select id,name,age from table_name; select id,name from table_name where id = 1; select id,name,gender,birthday,entry_date,job,salary,resume from employee; 练习: 查询表中所有学生的信息。 select * from exam; 查询表中所有学生的姓名和对应的英语成绩。 select name,english from exam; 过滤表中重复数据。distinct去重 select distinct * from exam;
distinct 针对的就是后面紧跟着的内容去重,再后面的字段就是增加的显示内容
SELECT DISTINCT name from exam;
查询结果:
SELECT DISTINCT name,name,chinese from exam;
Select语句(2)
• 在select语句中可使用表达式对查询的列进行运算
• 在select语句中可使用as语句
SELECT column as 别名 from 表名;
基本语句 select name,chinese+10,math+10,english+10 from exam; select name,chinese+10 as chinese from exam; 别名关键字 as --对于某些字段需要使用新名字展示,可以调用别名as进行修改。 select name,chinese+10 as chinese from exam; 练习 在所有学生分数上加10分特长分显示。 select name,chinese+10,math+10,english+10 from exam; 统计每个学生的总分。 select name,math+chinese+english from exam; 使用别名表示学生总分。 select name,math+chinese+english as sum from exam; select name,math+chinese+english sum from exam;
Select 语句3---where
使用where子句,进行过滤查询。练习: 查询姓名为"赵云"的学生成绩 select * from exam where name='赵云'; 查询英语成绩大于90分的同学 select name,english from exam where english >90; 查询总分大于220分的所有同学 select name,math+chinese+english as sum from exam where math+chinese+english > 220; 数据库关键字执行顺序: from > where > select
在where子句中经常使用的运算符
比较运算符 |
> < <= >= = <> 大于、小于、大于(小于)等于、不等于 |
between ...and... |
显示在某一区间的值 |
in(set) | 显示在in列表中的值,例:in(100,200) |
like ‘张pattern’ |
模糊查询%_ select *from user where name like"%张%" |
is null |
判断是否为空 select * from user where id is null |
ifnull(原值,替代值) |
如果原值为null,则使用代替值 select ifnull(score,0) from exam; |
逻辑运算符 |
|
and | 多个条件同时成立 |
or | 多个条件任一成立 |
not |
不成立,例:where not(salary>100); |
Like语句中,% 代表零个或多个任意字符,_ 代表一个字符,例first_name like ‘_a%’;
查询英语分数在 80-100之间的同学。 select * from exam where english between 80 and 100; 查询数学分数为75,76,80的同学。 select * from exam where math in(75,76,80); 查询所有姓张的学生成绩。 select * from exam where name like "张%"; 查询数学分>70,语文分>80的同学。 select * from exam where math>70 and chinese>80; 查询数学分>70或者语文分>80的同学。 select * from exam where math>70 or chinese>80; 查询数学分不在60分以下的同学。 select * from exam where not(math<60) ; 查询数学缺考人员。成绩为null select * from exam where math is null; 查询每一个人的成绩总和。 select name,ifnull(math,0)+chinese+english from exam;
select 语句---order by
对于查询结果排序展示。 order by 关键字需要放在查询语句的最后。 order by 关键字执行顺序是在所有关键字的最后。 基本语句: select * from table_name order by column_name asc|desc; 对语文成绩排序后输出。 select chinese from exam order by chinese; 对总分排序按从高到低的顺序输出 select ifnull(math,0)+chinese+english as sum from exam order by sum desc; 对姓李的学生成绩排序输出 select * from exam where name like "张%" order by ifnull(math,0)+chinese+english ; insert into exam values(null,"张无忌",100,100,90);
4.聚合函数
count(列名)返回某一列,行的总数
|
Select count(*)|count(列名) from tablenam [WHERE where_definition] |
4.1聚集函数-count 计数 用于返回满足查询条件的行数。 基本语句: select count(*)|count(column_name) from table_name; select count(*) from exam; select count(math) from exam; 练习: 统计一个班级共有多少学生? select count(name) from exam; 统计数学成绩大于90的学生有多少个? select count(math) from exam where math>90; 统计总分大于250的人数有多少? select count(ifnull(math,0)+chinese+english) from exam where ifnull(math,0)+chinese+english>250; 扩展: count(*)和count(1)都可以对表格的行数进行计数操作。 count(1)的执行效率比count(*)稍高。 count(1)可以理解为是对表格中的第一个字段进行计数。
4.2sum函数
Sum函数返回满足where条件的行的和
|
Select sum(列名){,sum(列名)…} from tablename[WHERE where_definition] |
基本语句: select sum(column_name) from table_name; 练习: 统计一个班级数学总成绩? select sum(math) from exam; 统计一个班级语文、英语、数学各科的总成绩 select sum(chinese),sum(english),sum(math) from exam; 统计一个班级语文、英语、数学的成绩总和 select sum(ifnull(math,0)+chinese+english) from exam; 统计一个班级语文成绩平均分 select sum(chinese)/count(chinese) from exam; 注意:sum仅对数值起作用,否则会报错。 注意:对多列求和,“,”号不能少。
4.3
AVG函数返回满足where条件的一列的平均值
|
Select avg(列名){,avg(列名)…} from tablename [WHERE where_definition] |
基本语句 select avg(column_name) from table_name; select avg(chinese) from exam; 练习: 求一个班级数学平均分? select avg(math) from exam; 求一个班级总分平均分? select avg(ifnull(math,0)+chinese+english) from exam;
4.4max和min函数
Max/min函数返回满足where条件的一列的最大/最小值
|
Select max(列名)from tablename [WHERE where_definition] |
对于满足条件的查询结果求最大最小值展示。 练习: 求班级最高分和最低分(数值范围在统计中特别有用) select max(ifnull(math,0)+chinese+english),min(ifnull(math,0)+chinese+english) from exam;
select ----分组操作
使用group by 子句对列进行分组
|
SELECT column1, column2. column3.. FROM table group by column having ... |
基本语句 select * from table_name group by column_name; select * from m group by id; 练习:对订单表中商品归类后,显示每一类商品的总价 select product,sum(price) from orders group by product; • 使用having 子句 对分组结果进行过滤 练习:查询购买了几类商品,并且每类总价大于100的商品. select product,sum(price) from orders group by product having sum(price)>100; 总结: 在分组之前添加条件判断使用关键字where。 在分组之后添加条件判断使用关键字having。 在使用where的地方可以使用having替换。但是使用having的地方不可以使用where替换。
having说虽然比where要好,但是我们不能一直采用的是一个having 要是全是having 的话我们就不知道是分组前还是分组后的条件判断,要重新解读sql语句
6.外键约束
- 外键:
- 用来通知数据库表与表字段之间的对应关系, 并让数据库帮我们维护这样关系的键就叫做外键
- 外键作用: 维护数据的完整性 一致性
- 定义外键约束
foreign key(ordersid) references orders(id) |
这段话的意思是本表中的ordersid字段设置为外键,依赖于或者这个外键受到的约束来自于Parts表的model字段。
案例:
新建部门表dept(id,name)
通过外键约束建立与员工表emp关系 也就是员工表中有个字段 dept_id 作为员工表的外键,它受制于约束 部门表的id
|
create table dept( id int primary key auto_increment, name varchar(20) ); |
|
insert into dept values(null, '财务部'); insert into dept values(null, '人事部'); insert into dept values(null, '科技部'); insert into dept values(null, '销售部'); |
|
create table emp( id int primary key auto_increment, name varchar(20), dept_id int, foreign key(dept_id) references dept(id) ); |
|
insert into emp values(null, '张三', 1); insert into emp values(null, '李四', 2); insert into emp values(null, '老王', 3); insert into emp values(null, '赵四', 4); insert into emp values(null, '刘能', 4); |
创建部门表和员工表 create table dept( id int primary key auto_increment, name varchar(20) ); insert into dept values (null,'财务部'),(null,'人事部'),(null,'科技部'),(null,'销售部'); create table emp( id int primary key auto_increment, name varchar(20), dept_id int, foreign key(dept_id) references dept(id) ); insert into emp values (null,'张飞',1),(null,'关羽',2),(null,'刘备',3),(null,'赵云',4); delete from dept where id = 3; insert into emp values(null,'背景',5);
7.多表查询
数据库中经常涉及到多张表一起查询的情景,可以使用多表查询的方式解决。 a. 笛卡尔积查询: select * from dept,emp; i. 笛卡尔积查询结果: 左边表的行数*右边表的行数 = 查询结果数量 +----+--------+----+------+---------+ | id | name | id | name | dept_id | +----+--------+----+------+---------+ | 1 | 财务部 | 1 | 张飞 | 1 | | 2 | 人事部 | 1 | 张飞 | 1 | | 3 | 科技部 | 1 | 张飞 | 1 | | 4 | 销售部 | 1 | 张飞 | 1 | | 1 | 财务部 | 2 | 关羽 | 2 | | 2 | 人事部 | 2 | 关羽 | 2 | | 3 | 科技部 | 2 | 关羽 | 2 | | 4 | 销售部 | 2 | 关羽 | 2 | | 1 | 财务部 | 3 | 刘备 | 3 | | 2 | 人事部 | 3 | 刘备 | 3 | | 3 | 科技部 | 3 | 刘备 | 3 | | 4 | 销售部 | 3 | 刘备 | 3 | | 1 | 财务部 | 4 | 赵云 | 4 | | 2 | 人事部 | 4 | 赵云 | 4 | | 3 | 科技部 | 4 | 赵云 | 4 | | 4 | 销售部 | 4 | 赵云 | 4 | +----+--------+----+------+---------+ select * from dept,emp where dept.id = emp.dept_id; b. 内连接查询 在笛卡尔积的查询基础之上,获取左边表有且右边表也有的数据,这种查询方式称之为内连接查询。 select * from dept,emp where dept.id = emp.dept_id; inner join … on inner join前后书写两张表, on后添加两张表连接时的条件。 select * from dept inner join emp on dept.id = emp.dept_id; +----+--------+----+------+---------+ | id | name | id | name | dept_id | +----+--------+----+------+---------+ | 1 | 财务部 | 1 | 张飞 | 1 | | 2 | 人事部 | 2 | 关羽 | 2 | | 3 | 科技部 | 3 | 刘备 | 3 | | 4 | 销售部 | 4 | 赵云 | 4 | +----+--------+----+------+---------+ c. 外连接查询 i. 左外链接查询 在内连接的查询基础之上,获取左边表有但右边表没有的数据,这种查询方式称之为左外连接查询。 select * from dept left join emp on dept.id = emp.dept_id; 使用别名查询: select * from dept d left join emp e on d.id = e.dept_id; +----+--------+------+------+---------+ | id | name | id | name | dept_id | +----+--------+------+------+---------+ | 1 | 财务部 | 1 | 张飞 | 1 | | 2 | 人事部 | 2 | 关羽 | 2 | | 3 | 科技部 | 3 | 刘备 | 3 | | 4 | 销售部 | 4 | 赵云 | 4 | | 5 | 保安部 | NULL | NULL | NULL | +----+--------+------+------+---------+ ii. 右外连接查询 在内连接的查询基础之上,获取左边表没有但右边表右的数据,这种查询方式称之为右外连接查询。 select * from dept right join emp on dept.id = emp.dept_id; +------+--------+----+------+---------+ | id | name | id | name | dept_id | +------+--------+----+------+---------+ | 1 | 财务部 | 1 | 张飞 | 1 | | 2 | 人事部 | 2 | 关羽 | 2 | | 3 | 科技部 | 3 | 刘备 | 3 | | 4 | 销售部 | 4 | 赵云 | 4 | | NULL | NULL | 5 | 背景 | 6 | +------+--------+----+------+---------+ iii. 全外连接查询 在内连接的查询基础之上,获取左边表有但右边表没有的数据和左边表没有但右边表右的数据,这种查询方式叫做全外连接查询。 select * from dept full join emp on dept.id = emp.dept_id;#mysql中没有fulljoin 可以通过union关键字实现全外连接查询的结果。 select * from dept left join emp on dept.id = emp.dept_id union select * from dept right join emp on dept.id = emp.dept_id; +------+--------+------+------+---------+ | id | name | id | name | dept_id | +------+--------+------+------+---------+ | 1 | 财务部 | 1 | 张飞 | 1 | | 2 | 人事部 | 2 | 关羽 | 2 | | 3 | 科技部 | 3 | 刘备 | 3 | | 4 | 销售部 | 4 | 赵云 | 4 | | 5 | 保安部 | NULL | NULL | NULL | | NULL | NULL | 5 | 背景 | 6 | +------+--------+------+------+---------+
8.子查询
1、where型子查询:把内层查询的结果作为外层查询的比较条件
查询每个类别下id最大的商品(使用where子查询实现)
SELECT goods_id,goods_name,cat_id,shop_price FROM goods WHERE goods_id IN (SELECT MAX(goods_id) FROM goods GROUP BY cat_id);
2、from型子查询:把内层的查询结果当成临时表,供外层sql再次查询。查询结果集可以当成表看待。临时表要使用一个别名。
2.1 查询每个类别下id最大的商品(使用from型子查询)
:mysql > SELECT goods_id,goods_name,cat_id,shop_price FROM
-> (SELECT goods_id,goods_name,cat_id,shop_price FROM goods ORDER BY cat_id ASC,goods_id DESC) AS tmp
-> GROUP BY cat_id;
3.exists型子查询:把外层sql的结果,拿到内层sql去测试,如果内层的sql成立,则该行取出。内层查询是exists后的查询。
从类别表中取出其类别下有商品的类别(如果该类别下没有商品,则不取出),[使用exists子查询]
:mysql> SELECT c.cat_id,c.cat_name FROM category c WHERE EXISTS (SELECT 1 FROM goods g WHERE g.cat_id = c.cat_id);
exists子查询,如果exists后的内层查询能查出数据,则表示存在;为空则不存在。
4.1 使用 any 查出类别大于任何一个num值的类别。
ANY关键词必须后面接一个比较操作符。ANY关键词的意思是“对于在子查询返回的列中的任一数值,如果比较结果为TRUE的话,则返回TRUE”。
:mysql> SELECT cat_id,cat_name FROM category WHERE cat_id > ANY (SELECT num FROM nums);
4.2 使用 in 查出cat_id 等于num的类别
:mysql> SELECT cat_id,cat_name FROM category WHERE cat_id IN (SELECT num FROM nums);
in 的效果 跟 =any 的效果是一样的。
4.4 使用 all 查询
词语ALL必须接在一个比较操作符的后面。ALL的意思是“对于子查询返回的列中的所有值,如果比较结果为TRUE,则返回TRUE。”
子查询总结:
1. where型子查询:把内层查询的结果作为外层查询的比较条件。
from型子查询:把内层的查询结果当成临时表,供外层sql再次查询。查询结果集可以当成表看待,临时表需要一个别名。
exists型子查询:把外层sql的结果,拿到内层sql去测试,如果内层的sql成立,则该行取出。内层sql是exists后的查询。
2. 子查询也可以嵌套在其它子查询中,嵌套程度可以很深。子查询必须要位于圆括号中。
3. 子查询的主要优势为:
子查询允许结构化的查询,这样就可以把一个语句的每个部分隔离开。
有些操作需要复杂的联合和关联。子查询提供了其它的方法来执行这些操作。
4. ANY关键词必须后面接一个比较操作符。ANY关键词的意思是“对于在子查询返回的列中的任一数值,如果比较结果为TRUE的话,则返回TRUE”。
词语 IN 是 =ANY 的别名,二者效果相同。
NOT IN不是 <> ANY 的别名,但是是 <> ALL 的别名。
5. 词语ALL必须接在一个比较操作符的后面。ALL的意思是“对于子查询返回的列中的所有值,如果比较结果为TRUE,则返回TRUE。”
6. 优化子查询
①. 有些子句会影响在子查询中的行的数量和顺序,通过加一些限制条件来限制子查询查出来的条数。例如:
SELECT * FROM t1 WHERE t1.column1 IN (SELECT column1 FROM t2 ORDER BY column1);
SELECT * FROM t1 WHERE t1.column1 IN (SELECT DISTINCT column1 FROM t2);
SELECT * FROM t1 WHERE EXISTS (SELECT * FROM t2 LIMIT 1);
②. 用子查询替换联合。例如:
SELECT DISTINCT column1 FROM t1 WHERE t1.column1 IN (SELECT column1 FROM t2);
代替这个:SELECT DISTINCT t1.column1 FROM t1, t2 WHERE t1.column1 = t2.column1;
9.备份
扩展:
1. mysql查询关键字执行顺序:
查询中用到的关键词主要包含六个,并且他们的顺序依次为 :
select--from--where--group by--having--order by
其中select和from是必须的,其他关键词是可选的。
这六个关键词的执行顺序,与sql语句的书写顺序并不是一样的,而是按照下面的顺序来执行
from--where--group by--having--select--order by。
注意:
i. 虽然select在having后执行,但是mysql中仍然可以在having中使用select语句定义的别名。
原因分析:mysql在查询的时候会产生一个临时表,所有的字段名称(别名)在临时表中已经产生,产生了临时表之后才会进行having操作。也就是说mysql内部有一定的解析顺序,解析顺序select优先于having。在这里我个人认为是mysql可能没有将这一点做规范。
i. Oracle中having无法使用select语句内的别名。
2. insert into 和replace into和merge into
a. insert into是mysql的基本插入语句。
b. replace into 是mysql中的代替插入语句,可以理解为insert into的升级版。replace into在执行的时候,首先会根据指定的主键或者唯一索引判断当前表中是否存在指定的主键或索引,如果主键或唯一索引已经存在,则先将对应的索引的数据删除,然后在索引位置插入replace into中包含的数据。如果主键和唯一索引没有存在,则直接在索引位置插入replace into中包含的数据。
c. merge into 是oracle数据库中的代替插入语句。实现方式和replace into类似。
d. 执行效率:
i. 如果指定索引位置没有数据,insert into和replace into执行效率相差无几,二者效率相同。
ii. 如果指定位置索引已经存在,insert into语句不能正常执行,replace into语句可以正常执行。
e. 注意:虽然replace into比较好使用,但是也存在一定风险:
i. replace每次要重新分配自增id;
ii. replace中执行delete时, 在有外键的情况下会很麻烦;
iii. 如果delete时定义的有触发器, 则会被执行;
iv. 副作用也会被传播到replica slave.
f. 推荐使用INSERT INTO … ON DUPLICATE KEY UPDATE
ON DUPLICATE KEY UPDATE是mysql特有的一个sql关键字,只能在mysql中使用。
在MySQL数据库中,如果在insert语句后面带上ON DUPLICATE KEY UPDATE 子句,而要插入的行与表中现有记录的惟一索引或主键中产生重复值,那么就会发生旧行的更新;如果插入的行数据与现有表中记录的唯一索引或者主键不重复,则执行新纪录插入操作。
比如有这样一张表:
create table func(id int primary key,count int,birthday date);
insert into func values(1,1,'1990-09-09');--插入一条数据
insert into func values(1,1,'1990-09-09') on duplicate key update count = count+1;--表中有数据,删除原表数据,将新数据插入。
提示两行受到影响,说明先执行的删除操作,然后插入新的数据。
观察到没有任何新数据插入,count字段被更新。(count字段更新是因为刚刚的插入语句中书写了update count = count+1;)
如果不希望任何字段更新,可以写成如下格式:
insert into func values(1,1,'1990-09-09') on duplicate key update count = values(count);--再次执行,没有新数据插入到数据库中。
3. MySQL内置函数
请了解mysql内置函数。内置函数众多,不需要每一个都掌握,熟练掌握几个在以后使用即可。可以查看mysql官方文档学习内置函数。
4. 在已经存在的表中添加外键。(仅作为了解内容)
alter table tb_name add constraint fk_name foreign key (tb_name.id) references tb_stu(id);
例如:alter table emp add constraint forkey foreign key(dept_id) references dept(id);
该语句是在 tb_name表上添加一个外键约束,引用 tb_stu的主键,fk_name是约束的名字。
删除约束:alter table tb_name drop constraint fk_name ;
5. 外键的使用情景:
在不要求吞吐速度而对数据的正确性和安全性要求较高时,推荐使用外键。
如果面对高吞吐量,要求优先保证读取效率时,则不推荐使用外键。
6. 删除的时候使用别名:
原句:delete from employee where id = 1;
别名:delete e from employee as e where id =1;