mysql知识点回顾

https://www.bilibili.com/video/av19538278?p=2
https://blog.csdn.net/qixibalei/article/details/54340872
https://www.bilibili.com/video/av22645209/?spm_id_from=333.788.videocard.1
https://www.bilibili.com/video/av32042911/?p=37

1.结构梳理

公益一班的同学有就业登记表,成绩表,档案表,违纪表;这些表放在一个档案袋里,档案袋由王大婶来管理,王大婶管理着很多档案袋。这些表就是数据表,一班的档案袋就是一个数据库,而王大婶就是数据库管理系统或者数据库服务器。一个服务器下有多个库,一个库下有1到多张表,表中有多行多列数据。

2.配置环境变量
3.入门最基本语句
mysql -u root -p
show databases;
use 库名;#选库语句
show tables;
创建一个数据库create database 数据库名 [字符集];
create database gy1 charset utf8; 
use gy1;
删除数据库
drop database gy1;

把数据库改名 在mysql中,表/列可以改名,库不可以改名

mysql的配置文件为my.ini,从中可以查询mysql中的各个文件

建表语句create table stu(Snum int, Sname varchar(10))engine myisam charset utf8;

删除表 drop table stu;

给表该名  rename table oldname to newname;

insert into newstu values(1, ‘zhangsan’),(2,'wangwu'),(3,'lisi');

清空表数据 truncate 表名;

truncate相当于删除表在再重建一张同样结构的表,操作之后得到一张全新的表,而
delete是从删除数据行的层面来操作的。如果决定全删,truncate速度更快。

4.基本语句

(1)针对单个表的最基础的增删查改

乱码,因为cmd使用的是gbk,而我们创建的是utf8,所以要告诉服务器,
客户端使用的是GBK编码 set names gbk;

tee D:\1010.spl #tee这句话是把sql及结果都输出到一个sql文件中,便于之后查询

create table class (id int primary key auto_increment,sname varchar(40), gender
char(1) not null default '',salary decimal(6,2) not null default 0.00,fanbu smallint not null default 0)engine myisam charset utf8;

查看表的结构
desc 表名;

如果你插入所有列,不声明可以直接插入,但如果你插入几列需要声明。
id虽然是自增型,但插入时要赋值,列与值要一一对应

update 改的要素
改的哪张表
改的哪几列
改成什么值
update class set gender=‘男’,fanbu=123 where id=6;

where后面是表达式,只要where 表达式为真,则改行就发生更改

update class set fanbu=259 where gander='男' and salary>8000;

where 1表示为真,所有都满足

删除的学习,删除就是删除整行的数据,不存在删除一行中的某几列
delete from class where salary>8000;
query ok说明执行成功 0 rows afftected删除了0行

查的学习
查询3要素
查哪张表
查哪些列
查哪些行
select sname,company,salary from class where id=6;

(2)列类型

列类型
其实建表的过程就是建表头的过程,从术语上讲,建表的过程就是声明字段的过程
硬盘空间有限,所以我们建表时即要考虑内容又要考虑浪费
存储同样的数据,不同的列类型所占据的空间和效率是不一样的,这就是我们建表前学习列类型的意义 所以重点学列类型的存储范围与占据的字节关系

mysql三大列类型

数值型
整型
tinyint -128~127 0~255 1个字节8位 0000 0000 1111 1111
smallint 2个字节
计算机会将最高位当作符号位
0 000 0000 ---->0
0 111 1111 ---->127
1 000 0000 ---->-0
1 111 1111 ---->-127
二进制补码的问题---如上理解的话,+0,-0则重复了,浪费了一种存储的可能性,
因此计算机中的负数,不是照着“后面的绝对值直接乘-1得到的”而是用补码规则换算的
负数 = 决定值位-128

一般而言,设某字节N字节

N字节 8N位
0----->2^8N-1
-2^(8N-1) --->+2^(8N-1)-1

对于int型占4个字节42亿左右

int型不加特殊说明默认有符号
int系列的声明时的参数(M)unsigned zerofill
unsigned 表示无符号,可以影响存储范围
zerofill代表0填充,
M表示补0宽度,必须和zerofill连用,才有意义,即不够位数,用0填充
参数设置zerofill则同时必是unsigned类型

小数型
浮点数在计算机里表示是比较复杂的
234.87
23.487
小数点左边 能大到多少?
小数点右边 又能大到多少?
Float(M,D)
M叫“标度”---->代表“总位数”,而D是“精度”,小数位(代表小数右边的位数)

float(6,2) -9999.99~9999.99
float能存1038.10-38 如果M<=24,占4个字节,否则占8个字节

alter table tablename add 字段名 字段类型 约束条件;
alter table salary add bonus float(5,2) unsigned not null default 0.00;
用来表示数据中的小数除了float--浮点数,还有一种叫定点decimal,定点是把整数部分和小数部分分开存储的,比float精确,
float有时会损失精度
123456789.987654321 decimal占8个字节

字符串型
char(M) 定长字符串 0<=M<=255之间
char(10)代表能输入10个字符
varchar(M)变长字符串 M代表宽度, 0<=M<=65535(以ascii字符为例,utf822000左右)
可以想象成硬盘是连续的存储空间,若移动磁头去读取第三行的姓名,如果是定长的,
可以更快的获取,通过行数与行的长度计算出来文件指针的偏移量。但对于定长N,无论够不够指定长度都需要开辟N个长度,对于不够N个长度,用空格在尾部补够N个长度,浪费了尾部。
varchar(100)也是存储0-100个字符,不用空格补齐,varchar在存储数据时,每个数据都有1-2个字节的前缀,该前缀用来标志该列内容的长度,方便磁头获取数据。
concat函数,用来连接字符串用的。
select concat(ca,'!'),concat(vca,'!') from test;
char型如果不够M个字符,内部用空格补齐,取出时再把右侧空格删掉,这意味着如果右侧本 身有空格,将会丢失。
注意【char(M),varchar(M)限制的是字符不是字节】
char(2)charset utf8,能存两个utf8字符,比如‘中国’,一个汉字占3个字节

text文本类型,一般用来存储文章内容,新闻内容等,声明text列时,不必给默认值。

blob 二进制类型,用来存放图像,音频等二进制信息
意义:2进制,0-255都有可能出现。blob在于防止因为字符集的问题,导致信息丢失。
比如:一张图片中有0xFF字节,这个在ascii字符集认为非法,在入库的时候被过滤掉。

mysql5.7参考手册下载好后,解压,找到index文件打开即可以

日期/时间类型
2012-10-29

类型 说明 标准格式 范围 存储需求
date 日期 YYYY-MM-DD 1000-01-01到9999-12-31 3个字节
time 时间 HH-MM-SS -838:59:59和‘838:59:59’ 3个字节
datetime 日期时间 YYYY-MM-DD HH:MM:SS 1000-01-01 00:00:00到9999-12-31 23:59:59 8个字节
year 年份 YYYY 1901-2155 1个字节
timestamp 4个字节 1970-01-01 00:00:01到2038-01-19 03:14:07与datatime格式相同,但当不给它默认值时,它自动产生默认值,
提取当前时间

create table test5(id int,ts timestamp default CURRENT_TIMESTAMP)engine myisam charset utf8;
insert into test5 (id) values(1),(2),(3);

date型,存储年月日
1366字符集问题,需要告诉服务器你的客户端类型,set names gbk;
year还可以存0000年,代表出错啦 基数 256种变化
year类型还可以简写成两位
create table test7(ya year(2))engine myisam charset utf8;
insert into test7 values('95'),(12);
但是不推介这样,换算起来麻烦
[00-69]+2000
[70-99]+1900
即2位表示1970-2069

(3)表的增删查改

建表

表的优化,时间和空间的权衡,空间与时间是一对矛盾,空间换时间,时间换空间
定长与变长的选择
我们可以将某些变长的改为定长的,但对于某些更改会造成巨大浪费的,不进行更改,
将其中修改频率并不高的可以单独拿出来,另放一张表中。

在开发中,把频繁用到的信息,优先考虑效率,存储掉到一张表中,不常用的信息和比较占据
空间的信息和比较占据空间的信息优先考虑空间占用,存储到铺表中。

create table 表名(

列名1声明 列参数,
列名2声明 列参数,
列名3声明 列参数,
列名n声明 列参数,
)engine innodb/myisam charset utf8/gbk;

修改表的语法

一张表,创建完毕,有了N列,之后还有可能要增加或删除或修改列
Alter table 表名 add 列名称 列类型 列参数;

例:alter table m1 add birth date not null default '0000-00-00';

Alter table 表名 add 列名称 列类型 列参数 after 某列;[把新列指定加到某列后]

例:alter table m1 add gender char(1) not null default ''after username;

Alter table 表名 add 列名称 列类型 列参数 first;[把新列添加到第一列]

例:alter table m1 add pid int not null default 0 first;

删除列

alter table 表名 drop 列名称;

修改列类型

alter table 表名 modify 列名 新类型 新参数;

alter table m1 modify gender char(4) not null default '';

修改列名及列类型

alter table 表名 change 旧列名 新列名 新类型 新参数;
alter table m1 change id uid int unsigned;

5种子句介绍
where
group by
having
order by
limit

ECShop官网下载 解压 商城 upload文件复制到相应地址重命名

将增删查改上升到哲学的高度

查看goods表的建表语句

show create table goods;

insert into test.goods select goods_id,cat_id,goods_sn,goods_name,click_count from gyshop.goods

where的常用运算符
比较运算符 不等于:!= , in between..and.

select goods_id,cat_id,good_name from goods where cat_id in(4,11);

cat_id在4,11这个集合里都满足。

select goods_id,cat_id,good_name from goods where shop_price between 100 and 500;

between..and..包括边界
in 是散点集合 between and 是区间

逻辑运算符 and优先级高于or

select goods_id,cat_id,good_name from goods where cat_id not in(3,11);
select goods_id,cat_id,good_name from goods where cat_id!=3 and cat_id!=11;
select goods_id,cat_id,good_name from goods where shop_price>=100 and shop_price<=300 or shop_price>=4000 and shop_price<=5000;
select goods_id,cat_id,good_name from goods where cat_id=3 and (shop_price<1000 or shop_price>5000) and click_count>=5;

无限极分类问题

模糊查询 like %是匹配符,匹配任意字符 用‘_’匹配任意单个字符

select goods_id,cat_id,good_name from goods where goods_name like '诺基亚%';
select goods_id,cat_id,good_name from goods where goods_name like '诺基亚N__';

重要理解--查询模型
把列看成变量,把where后面看成python中if后面的表达式,
哪些行被取出来?---哪一行能让表达式为真哪一行就能取出来。
把列看成变量,既然是变量,变量之间就可以进行运算

表里原来没有“market_price-shop_price”的列,这一列其实是一个运算的结果,术语叫“广义投影”,列的运算结果,可以当做列看,还可
以起个列别名

select goods_id, goods_name,(market_price-shop_price) as discount from goods where cat_id=3;

select goods_id, goods_name,(market_price-shop_price) as discount from goods where
market_price-shop_price>200;

表文件--where查询-->结果
where是对表中的数据发挥作用,having对where的查询结果进一步处理。

select goods_id, goods_name,substring(goods_name,4)from goods where goods_name like '诺基亚%';

select goods_id, goods_name,concat('HTC',substring(goods_name,4))from goods where goods_name like '诺基亚%';

统计函数

max()
select max(shop_price) from goods;
min()
select min(shop_price) from goods;
sum() 求和函数
select sum(goods_num) from goods;
avg() 求平均函数
select avg(goods_num) from goods;

count()计算行数的函数
select count() from 表名,查询的是绝对的行数,哪怕某行的所有字段全为null也计算。
而select count(列名)from 表名,查询的是该列不为null的所有的行数
select count(1) from goods;
用count(
)和count(1)哪个好?其实对于myisam引擎的表没有区别的,这种引擎内部有一计数器在维护着行数;Innodb的表,用count(*)直接读行数,效率很低,因为innodb真的要去数一遍。
select count(0) from goods;
select count(name) from goods;name有值则计数加1

上面是5个统计函数,单独使用意义不大,要和分组配合起来使用
select sum(goods_number) from goods group by cat_id;
分了组再统计
select goods_id,sum(goods_number) from goods;这个语句执行了,为什么把goods_id等于1取出来la?对于sql标准来说,这个语句是错误的,不能执行的,但是在mysql下是可以这么干的。

统计班级同学的姓名和平均年龄
语义上就解释不通,但是mysql中可以,把队列中第一个姓名返回
select cat_id ,avg(shop_price) from goods where cat_id=3;严格的讲,以group by a,b,c 为列,则select 的列只能在a,b,c中选择,语义上才可以没有矛盾。


select5中子查询关系图.png

查询出栏目的积压贷款金额,且筛选出积压金额>20000的栏目
用到了group与having

select cat_id,sum(goods_number*shop_price) as zhk from goods group by cat_id having zhk>20000;

查出挂科两门及两门以上的学生的平均分
第一步查出每个人的平均分

select name,avg(score) from result grou by name

第二步,计算出每个人挂科的情况

select name, subject,score,score<60 as g from result;

挂科数目就是g的sum结果

select name,avg(score),sum(score<60) as gks from result group by name having gks>=2;

这一个思路是逆向思维,先查出所有人的平均分,再筛选。

当最终结果集出来后可以进行排序order by

select goods_id,goods_name from goods where cat_id=4 order by shop_price desc;

order by 结果集中的列名 desc/asc
order by add_time asc按发布时间升序排列
order by shop_price desc 按价格降序排列
按栏目升序,再按栏目中的商品的价格进行升序排列

select goods_id,cat_id,goods_name,shop_price from goods order by cat_id asc,shop_price asc;

多字段排序,前面的列优先排
order by 列1 desc/asc,列2 desc/asc,列3 desc/asc

限制条目 limit

select goods_id,cat_id, goods_name,shop_price from goods where cat_id=3 order by shop_prise asc limit 10;

limt[offset,]N
offset 偏移量
N取出条目
offset如果不写,则相当于 limit 0,N
查询出本店价格最高的前三名
select goods_id,goods_name,shop_price from goods order by shop_price limit 0,3;
查询出本店最高的第3名到第5名 商品
取第3名到第5名,即意味着跳过第一,第二,因此偏移量offset是2,取第3,4,5条,即取3条,因此N=3

select goods_id,goods_name,shop_price from goods order by shop_price limit 2,3;

5个子句,3个子查询

子查询
查询最新商品

select goods_id,goods_name from goods where goods_id=(select max(goods_id) from goods);
select goods_id,goods_name from goods where goods_id in(select max(goods_id) from goods group by cat_id);

where型子查询
如果 where 列=(内层 sql)则内层sql返回的必是单行单列,单个值
如果where 列 in(内层sql)则内层sql只返回单列,可以多行

from型子查询
即内层sql的查询结果,当作一张临时表,供外层sql,再次查询。

select * from (select goods_id,cat_id,goods_name from goods order by cat_id asc,goods_id desc) as tmp group by cat_id;

exists 型子查询
是指 把外层sql的结果,拿到内层sql去测试,如果内层sql成立,则该行取出。

select cat_id,cat_name from category where exists (select * from goods where goods.cat_id=category.cat_id);

为什么建表时,列后面 not null default '',default 0
null是空,四大皆空的空,null的比较需要用特殊的字符 is null 和 is not null
碰到运算符,一律返回null;效率不高影响提高索引效果
因此,我们往往在建表时 not null default 0

mysql中的联合查询

集合的知识
高中时候学过的集合
集合的特点 无序性 唯一性
集合的运算 求并集,求交集,笛卡尔积(相乘)
笛卡尔积即集合的元素,做两两的组合
集合A(2,3,5)集合B(4,7) 集合A*B=什么?
集合((2,4),(2,7),(3,4),(3,7),(5,4),(5,7))

集合A有M个元素
集合B有N个元素
AB=C
C有多少个元素?答:M
N个

表与集合的关系
其实一张表就是一个集合,每一行就是一个元素
在数据库的操作上,如何操作表,完成集合相乘的效果?
直接用“,”隔开表明,查询即可
全相乘
select * from test10,test11;
ambiguous的意思是模糊不清的,如果在多表联查时,某一列名,在2张或2张以上表都有,则需要在列名前指定表名,即表名.列名

select goods_id ,minigoods.cat_id,goods_name,category.cat_id,cat_name from minigoods,category where minigoods.cat_id=category.cat_id;

左连接
假设A表在左边,不动,B表在A表的右边滑动
A表与B表通过一个关系来筛选B表的行
A left join B on 条件 条件为真,则B表对应的行取出
这一块形成的也是一个结果集,可以看成一张表设为C
既如此,可以对C表做查询,自然where,group,having,order by,limit照常使用
select goods_id,goods_name,cat_name from goods left join category on goods.cat_id=category.cat_id where goods.cat_id=4;

左连接,右连接,内连接 没有用NULL补齐
左连接,以left左边的表为基准
右连接,以right右边的表为基准

create table boy(bname varchar(20),other char(1))engine myisam charset utf8;
insert into boy values('屌丝'‘A’),(‘张飒’,'B'),(‘沙哈’,‘C’),('锁定',‘D’);
create table girl(gname varchar(20),other char(1))engine myisam charset utf8;

右连接
B right join A on 条件
注意:既然左右连接可以互换,尽量用左连接,出于移植时兼容性的考虑。

内连接
都满足条件的留下

select boy.*,girl.* from boy inner join girl on boy.other=girl.other;

如果从集合的角度:A inner join B 和 left/right join的关系
内连接是左右连接的交集

在mysql中不支持外连接
在mysql中如何达到外连接的效果?
select hid,tname,mres,gid,matime from m left join t on m.hid=t.tid;

select hid,t1.tname,mres,gid,t2.tid,matime from m left join t as t1 on m.hid=t1.tid left
join t as t2 on m.gid=t2.tid where matime between '2006-06-01' and '2006-07-01';

Union 合并2条或多条语句的结果 连接查询
语法
sql1 union sql2
select goods_id,goods_name,shop_price from goods where shop_price <3000;
select goods_id,goods_name,shop_price from goods where shop_price >4000;
将以上2个语句的结果拼接起来就可以了,以上两个sql语句取出的列名相同,所以union合并时不用起别名
select goods_id,goods_name,shop_price from goods where shop_price <3000 union
select goods_id,goods_name,shop_price from goods where shop_price >4000;
union合并的是结果集,并不区分来自于哪张表
select user_name,msg_content,msg_time from feedback where msg_status=1;
select user_name,content as msg_content,add_time as msg_time from comment where status=1;

列名不同取别名
select user_name,msg_content,msg_time from feedback where msg_status=1 union
select user_name,content as msg_content,add_time as msg_time from comment where status=1;

如果列名不一样,不起别名,是否还可以用union?
select user_name,msg_content,msg_time from feedback where msg_status=1 union
select user_name,content,add_time from comment where status=1;
可以,而且取出的最终列名以 第1条sql的列名为名

union的使用范围:只要结果集中列数一致就可以使用

union的结果集仍可以排序
select goods_id,goods_name,shop_price from goods where shop_price <3000 union
select goods_id,goods_name,shop_price from goods where shop_price >4000 order by shop_price asc;
order by 是针对结果集进行排序
使用order by 的注意事项
(select goods_id,cat_id,goods_name,shop_price from goods where cat_id=4 order by shop_price desc)union (select goods_id,cat_id,goods_name,shop_price from goods where cat_id=5 order by shop_price desc) order by shop_price asc;
外层语句还要对最终结果再次排序,因此,内层的语句的排序,就没有意义;因此内层的order by 语句单独使用,在执行期间,就被Mysql的代码分析器给优化掉了,内层的order by必须能够影响结果集时,才会有意义。比如:配合limit使用。

(select goods_id,cat_id,goods_name,shop_price from goods where cat_id=4 order by shop_price desc limit 3)union (select goods_id,cat_id,goods_name,shop_price from goods where cat_id=5 order by shop_price desc limit 2);这一次内层的order by 发挥了作用,因为有limit,order会实际影响结果集,有意义。

如果union 后的结果有重复(即某两行或N行,所有的列值都一样)怎么办?
答:这种情况是很常见的,默认会去重;如果不想去重,可以union all
select * from test12 union all select * from test13;
select id,sum(num) from (select * from a union all select * from b) as tep group by id;

(4)mysql中的函数

mysql中的函数
1数学函数
abs(x) 返回x的绝对值
bin(x)
select bin(4);
hex(x)
floor(x)对小数取整,去除小数,向下取整
ceiling()向上取整
rand()随机生成0-1之间的数
2聚合函数
group_concat()返回由属于一组的列值连接组合而成的结果
3字符串函数
concat()
ascii()
select ascii(a);
length()计算字节数
char_length()计算字符数
utf8编码中文占3个字节 gbk编码中文占2个字节
reverse() 反转字符串
position( str in string),索引从1开始数
right(str,N)取出最右边N个字符

select *,right(email,length(email)-position('@'in email)) from test1;
4.日期时间函数
now() 返回datatime格式
curdate()返回date格式
curtime()返回时间部分
查询某日是那周的第几天
select dayofweek('2012-10-31');注意在西方周日是第一天
计算今天是2019年的第几周
select week(curdate());
select sum(num),week(dt) as wk from jiaban group by wk;
5.加密函数
md5
select md5('1111111')
良好的加密1.不可逆 2.碰撞性低(重复的结果低)
6.控制流程函数
case 值
when 某种可能
then 返回值

when 另一种可能值
then 返回值

else 默认值

end

select sname,
case gender
when 1
then '男'
when 0
then ‘女’
else ‘春’
end as xingbie
from test15;

if(表达式1,表达式2,表达式3) 相当于3元运算符 表达式1为真则返回表达式2,否则返回表达式3
判断性别,女士优先
select sname,if(gender=0,'优先',‘等待’)as VIP from test5;

ifnull的用法,判断第1个表达式是否为null,如为null,返回第2个表达式的值,如不为null,返回第一个表达式。
select ifnull('aaaa',0)
select

7.系统调试函数
select user();user()函数返回‘用户及所在主机’,判断自己的身份
select database();database()返回当前正在操作的库名
select version(); version()判断数据库版本
如果mysql函数和python函数都实现某个功能,优先用哪一个?
1.mysql的函数肯定是要影响查询的速度,应该在建表时,通过合理的表结构减少函数的使用。
比如email,按@前后拆分
2.如果确实要用函数,比如 时间的格式化,在mysql里用date_format,在python中date可以实现,优先放在业务逻辑层,即python层处理。
3.在查询时使用了函数,最大的一个坏处,以date_format(A),则A列的索引将无法使用。
举例:select name,email from table where right(position(email)) ='qq.com';
email列是有索引的,可以加快查询速度,但因为你使用的并不是email列,而是函数处理后的email的返回值。因此,email列的查询就非常缓慢了
总结:where条件中,对某列使用了函数,由此列的索引不发挥作用。

(5)视图

视图view
在查询中我们经常把查询结果当成临时表来看,但当表中数据发生变化时,临时表就没有了意义,所以我们引入视图
view是什么?view可以看作一张虚拟表,是表通过某种运算得到的一个投影,当表中数据发生变化时,视图也发生相应的变化;
select cat_id,avg(shop_price) as pj from goods grooup by cat_id order by pj desc limit 3;

如何创建视图?
答:建视图的时候,我们要指定视图的列名与列类型吗?
不要,它是个影子,继承了上面的字
不需要,只是一种关系
既然视图只是表的某种查询的投影,所以主要步骤在于查询表上查询的结果命名为视图就可以了

创建视图的语法
create view 视图名
as
select语句

视图一旦创建完毕,就可以像表一样查询

视图有什么用呢?
1.可以简化我们的查询
比如:复杂的统计时,先用视图生成一个中间结果,再查询视图
2.更精细的权限控制
比如某张表,用户表为例,现在呢,2个网站搞合作,可以查询对方网站的用户
需要向对方开放用户表的权限,但是又不想开放用户表的密码字段
create view vuser
as
select user_id,username,email from user;
开放这个视图的权限给对方
3.数据多,分表时可以用到
比如:小说站,article 表,1000多万篇
分成article1,article2,article3,...,article5,这5张表,每张表200万条,查询小说时不知在哪张表
create view article as
select title from article1 union select title from article2 union select title from article3;

表与视图数据变化时的相互影响问题
表的数据变化要影响到视图的变化
视图变了,表如何变化?
视图在某种情况下,也是可以修改的
要求:视图的数据和表的数据一一对应,就像函数的映射
表-->推出视图对应的数据
视图-->推出表对应的数据

drop view 视图名;
视图是表的投影,它并不存储真实的数据;
一一对应是指:根据select关系,从表中取出的行,只能计算出视图中确定的一行;反之,视图中任意抽一行,能够反推出表中的确定的一行
对于一些简单视图,他在发挥作用的过程中,并没有建立临时表,而只是把条件存起来,下次来查询,把条件一合并,直接去查表。

思考:相比于建临时表,哪个速度快?
建表:查询--》形成临时表--》查询临时表

叠加:合并条件--》查询表

到底要不要建临时表,还是合并语句

algorithm=merge 合并查询语句
temptable 临时表
underfined 未定义,由系统判断

对于简单的查询建立临时表的话,开销有点大,这时我们可以指定algorithm选项为merge
create algorithm=merge view v2
as
select * from goods where shop_price>300;

select goods_id,goods_name,shop_price from v2 where shop_price < 500;
虽然从结果上看不出结果,但是这个v2视图,并没有建立临时表,而是直接合并查询条件
有的时候,复杂查询必须建立临时表,比如:计算每个栏目下的最高商品
create view v3
as
select * from goods order by cat_id asc,shop_price desc;
下次再让你查每个栏目最高的商品价格
select * from v3 group by cat_id;
思考:如何合并这两个语句?
如果这样select * from goods order by cat_id asc,shop_price desc group by cat_id;
合并后,语句出错了,此时语句不能进行合并,只能建立临时表。
create algorithm=temptable view v3
as
select goods_id,cat_id,goods_name,shop_price from goods order by cat_id asc,shop_price desc;
这张表,明确指定了生成临时表,如果拿不准用什么,algorithm=undefined,让系统为我们做决定就OK了

(6)乱码问题
乱码问题
1.编码问题
计算机里,只有010101,而人的世界里,有文字,有图片,有声音...
01--->文字对应起来
人为的约定
65——》A
66——》B
...
...
0100 0001 [A,65] 规则
2进制编码到字符的映射,就是字符集。

看自己的键盘
A-Z
a-z
+-*/&^%
不超过127个

美国人在造计算机的时候,就没考虑到,还有其他的字符。
1111 1111
0000 0000 256种值
1个字节8个位就足够了
事实上,7个位就够了,因为7个位,可能表示128种变化.
ascii
0-127来表示
0xxx xxxx,最高位始终是0

到了中国
常用的汉字2000多,生僻汉字不用说
1个字节不够,任你变,不过256种。

思考:用2个字节来表示
[][]
0000 0000 0000 0000
1111 1111 1111 1111
0->65535,6万多种组合,够用了.
GB2312字符集
[202][197]假如代表 中
[69][197]代表?69和197整个理解,还是单理解成E
歧义:就是因为单字节的小于127的值,正好是ascii的值。如果就严格的2字节绑定,就理解为中文,则gb2312不能识别英文了。

问:如何兼容ascii,又能双字节表示中文?
ascii 0-127
0xxx xxxx
干脆 gb2312完全不占用0-127.

我的组合来自于
[129-255][129-255]
130 140 97 95 134 198
看:能几个中文,几个英文?
但是,中文的组合数,也少了。
只能组合10000+
事实上,GB2312只能容纳6000多字

有些常用的无法容纳,GBK出现,兼容GB2312
GBK的第二个字节,不在局限于129-255了,<127的也能用
148 35 65 179 87
问:几个中文,几个英文?
总结:碰到>128的,就再往后找一字节,2字节理解成中文,继续找

[65-255]
128*190 =24320

中国GBK
[137][134]->中
到了日本呢?
[137][134]->其他字的意思

ANSI 代表本地字符集 本地化编码
在中文操作GBK
在日本 JIS

解决了多字节之后,又遇到一个问题----世界各国的字符集的兼容问题

终极大招:Unicode 国际化字符集
Unicode是一个世界通用的码表
假设00000000 0000 0041->A
....................中
....................代表其他
全世界的范围的字符,统一分配一个标号,这样不会乱了
Unicode用4个字节,来编码
2^32 40多亿,天文数字,足够用了
但我们常用的,集中在前65535个字符里.2个字节就够了.
但是,unicode只负责分配编号用的,而且都用4个字节来分配编号。

你负责编号,我负责在不改变你编号的基础上,简化字节.
假设0000 0000 0000 0000 0000 0000 0000 0041-->A
0000 0041-->A
把高位浪费的0值,用一定的规则舍弃,形成的编码方式称为Unicode转换格式(unicode transformation format),简称UTF
例如:如果一个仅包含基本7位ASCII字符的Unicode文件,如果每个字符都使用2字节的原unicode编码传输,其第一个字节的8位始终为0,这就造成了比较大的浪费。对于这种情况可以使用UTF-8编码,这是一种变长编码,它将基本7位的ascii字符仍用7位编码表示,占用一个字节,首位补零,而遇到和其他unicode字符混合的情况,将按一定算法转换,每个字符用1-3个字节编码。

unicode与utf-8的关系,就像原文件---->压缩文件的关系
问:给定unicode字符-->utf-8的二进制值?
可以
问:给定utf-8的二进制值--->unicode字符?
可以
utf8占几个字节呢?
不可能定长,否则压缩还有什么意义 1-6个字节
23 179 234 123
变长,如何确定字符的边界?
看Unicode第一个字节10000000 1个字节
11000000 2个字节
11100000 3个字节
11110000 4个字节
11111000 5个字节
11111100 6个字节
如何截取utf8(各国语言都有),无乱码?
答:从头开始,取一个字节。
通过位运算,计算连续的1的个数,如为0,则截取1个字节,如为N,则截取N个字节

从容量上看
GB2312 < GBK <UTF8

问:GBK中文经常在Java中,被转为utf-8,如何转的?
答:GBK也是和unicode有对应关系的,GBK转换为unicode再转换为utf8

乱码是如何形成的?
1.解码时与实际编码不一致(可修复) 编码和解码不一致,文本是utf8,结果浏览器用gbk编码方式解码
2.传输过程中,编码不一致,导致字节丢失(不可修复)
utf-8-->转成GB2312,
utf8容量大 ,GB2312容量小 , 可能丢失字节
假设客户端是GBK的,服务器是UTF8的,那么如何将客户端的数据存到服务器的数据库中,
必定中间有一个转换---连接器
连接器的特性:连接客户端与服务器
客户端的字符先发给连接器,连接器根据情况按照一种编码确定将其是否转换,临时存储;再次转换为服务器需要的类型

要想不乱码,需要指定客户端的编码让连接器不理解错误,这样就不会存入错误的数据,往回取得时候,我们需要告诉连接器,如果你从服务器返回,应该给我转什么格式,一共3个参数,客户端的发送的编码,连接器使用的编码,获取的返回数据的编码

当前的情况是,客户端GBK,服务器最终存UTF8
明确的告诉服务器,我的客户端是GBK的
set character_set_client=gbk;
再告诉连接器使用utf8
set charset_set_connection=utf8;
再告诉,如果返回值,请返回GBK的结果
set character_set_results=gbk;

如果client,conn,results都是GBK,可以简写,简写成set names gbk;

牵涉到数据库,想不乱码
1.正确指定客户端的编码
2.合理选择连接器的编码
3.正确指定返回内容的编码
记事本默认 ansi gbk
联通
其实记事本在打开的时候,也分不清你的编码,‘猜’,分析编码的特点,推测的。。。

bom信息

utf8中文截取无乱码
思路
如果你看到如下字节,
42 DC 34 af aa
想截取无乱码,那就说明,你知道
从42开始截几个字节,作为一个字符,比如截取1个,截取出来42,再从DC截,你得知道,从DC往后是几个字节组成一个字符。所以关键在于如何判断一个utf8字符的字节数?
答:可以到wiki上查询utf-8的编码规则,那是最权威的
查阅后得知
最高字节
0xxx xxxx 1个字节
11xx xxxx 2个字节
111x xxxx 3个字节
1111 xxxx 4个字节...
mysql编码设定
文件导入
source 文件路径
show variables like 'char%';
服务器的编码设定如何改变?
在mysql安装包的文件目录下找到my.ini的配置文件,将其中的字符集合理更改,然后重新启动服务器
如何改数据库表的编码设定?
查看表的字符集
show create table 表名;
更改表的字符集
alter table 表名 character set utf8;
如何更改列的字符集?
alter table 表名 change 旧名 新名 varchar(20) character set utf8 not null;

解决多张拥有数据的表的字符编码问题?
1.导出表的结构
导出表的命令
mysqldump -uroot -p -default-character-set=utf8 -d 数据库名 >I:/麦学院/cc.sql
2.将数据库表的数据导出
mysqldump -uroot -p --quick --no-create-info --extended-insert --default-character-set=utf8 数据库名 >I:/麦学院/data.sql
3.删除原有数据库表
4.重新以新的方式创建数据库
mysql -uroot -p 数据库名 <I:/麦学院/cc.sql
在data.sql中添加set names 'utf8';
mysql -uroot -p 数据库名 <I:/麦学院/data.sql

(7)引擎
mysql引擎
不变的是数据,变化的是“存储的格式”
总结:engine 引擎就是mysql存储数据的不同方式
就像一部电影,“黄金甲”内容是一样的,rmvb,wmv,avi,1080p,MP4
myisam速度快,innodb事务安全支持
如果多人买火车票,只有一张火车票,几乎同时查询
银行转账 张三给李四转500块钱
像这样,2步或者N步,从逻辑上来讲,是一个“原子操作”,即要么成功,要么都不成功?
如何保障这种特性?
事务
原子性:就是2步或N步操作,逻辑上不可分割,通俗说:就是要么成功,要么都不成功
如何使用事务?
开启事务
start transaction;
update a2 set money = money +1000 where uname='zhangsan';
update a2 set money = money -1000 where uname='lisi';
两步都完成了,这个事务完成了
提交整个事务
commit;

再次开启事务,体现事务的原子特性
start transaction;
先给张三加500
update a2 set money = money +500 where uname='zhangsan';
接下来,扣李四500,但失败了,我故意把表名打错,模拟网络故障等失败情景
update a2 set moneys = money - 500 where uname='lisi';
扣李四的钱失败
整体的转账操作,从逻辑上讲,应该失败,即张三的钱,不能多500.
部分失败,则之前的成功操作怎么处理?答:回滚
rollback;

一致性:是指操作前后,值的变化,逻辑上成立
-500,+300,这样不行
比如tinyint来存钱,+300溢出了,也是失败

隔离性:是指事务结束前,每一步的操作带来的影响,别的会话看不见.

5.会话变量与全局变量

会话变量:表示一个客户端,当与服务端相关联的时候,你所设置的变量就是客户端所拥有的变量
show session variables;
简单快速查询
show session variables like 'auto%';
设置会话变量
set autocommit='off';或者set @@session.autocommit='off';

全局变量
show global variables;
show global variables like 'auto%';
set global autocommit='off';或者 set @@global.autocommit;

会话变量只是针对当前客户端有效,全局变量对整个mysql客户端有效

6.存储过程

存储过程:我们常用的操作数据库语言sql语句在执行的时候需要先编译,然后执行,而存储过程是一组为了完成特定功能的sql语句集,经编译后存储在数据库中,用户通过指定存储过程的名字并指定参数(如果该存储过程带有参数)来调用执行它。一个存储过程是一个可编程的函数,它在数据库中创建并保存。
创建存储过程的步骤:1.首先选中一个数据库2.改变分隔符,不让分号作为执行结束的标记,让存储过程作为一个单独的存储单元;通常情况下,改变分隔符的命令delimiter $$

use companys;
delimiter $$;

3.创建存储过程

create procedure p_hello()
begin
select 'hello';
select 'world';
end
$$;

恢复分隔符

delimiter ;

4.调用存储过程

call p_hello;

局部变量:在一定范围内有效,比如存储过程中
定义一个变量的语法:
declare 变量名 数据类型 default 默认值

use 数据库名;
dellimiter $$;
create procedure p_vartest()
begin
declare a varchar(20) default 'abc';
select a;
end
$$;

delimiter ;
call p_vartest;

加入参数

use 数据库名;
dellimiter $$;
create procedure p_vartest(in p_int int)
begin
select p_int;
set p_int=p_int + 1;
select p_int;
end
$$;

delimiter;
set @p_int =3;

call p_vartest(@p_int);

参数类型
in 存储过程认可之前的值,在存储过程中不修改变量值,只在存储过程中改变
out存储过程不认可之前的值,默认为null,在存储过程中修改变量值
inout:输入输出参数,该值可以在调用时指定,并可修改和返回

use 数据库名;
dellimiter $$;
create procedure p_vartest(out p_int int)
begin
select p_int;
set p_int=15;
select p_int;
end
$$;

delimiter;
set @p_int =3;
call p_vartest(@p_int);

控制流程

use companys;
delimiter $$;
create procedure p_showage(in age int)
begin
if age >=18 then
   select '成年人';
else
   select '未成年人';
end if;
end
$$;
delimiter ;
set @age=19
call p_showage(@age);
use companys;
delimiter $$;
create procedure p_showage(in age int)
begin
if age >=18 && age <=60 then
   select '成年人';
elseif age>=60 then
   select '老年人';
   else
   select ‘未成年人’
end if;
end
$$;
delimiter ;
set @age=67;
call p_showage(@age);

case控制流程

use companys;
delimiter $$;
create procedure p_showage(in v_empno int)
begin
 declare adds int;
case v_empno
when 1001 then
  set adds = 1500;
when 1002 then
  set adds = 3200;
else
  set adds = 1000;
end case;
end;
$$;
delimiter ;
set @v_empno=1001
call p_showage(@age);

drop procedure p_showage;

循环语句

while语句

use companys;
delimiter $$;
create procedure p_showage()
begin
declare i int default 1;
declare addresult int default 0;
while i <=100 do
  set addresult = addresult+i;
  set i = i+1;
  end while;
end
$$;
delimiter ;
call p_showage();

repeat语句

use companys;
delimiter $$;
create procedure p_updateGender()
begin
declare imin int default 1;
declare imax int default 1;
select min(emp_no) info imin from employees;
select max(emp_no) info imax from employees;
repeat
    if imin %2 = 0 then
     update employees set gender = 'F' where emp_no = imin;
    end if;
    set imin =imi +1;
    until imin >imax
end repeat;
end
$$;
delimiter ;
call p_showage();

loop语句

use companys;
delimiter $$;
create procedure p_updateHire()
begin
declare imin int default 1;
declare imax int default 1;
select min(emp_no) into imin from employees;
select max(emp_no) into imax from employees;
myloop:loop
    if imin %2=1 then
     update employees set hire_date='1999-12-11' where emp_no=imin;
   end id;
   set imin = imin+1;
   if imin > imax then
   leave myloop;
   end if;
end loop;
end
$$;
delimiter ;
call p_updateHire();

定义条件和处理:当我们有程序代码出错时,会提醒出错的位置,然后继续下面的程序

declare continue handler for sqlstate '错误代码值' set 变量=变量值
use 数据库名;
delimiter $$;
create procedure p_insertDemo2()
begin
declare continue handler for sqlstate '23000' set @x=1;
insert into userinfo(userid,username,userpwd)values(1,'ui','123');
insert into employees(emp_no,birth_date,first_name,last_name,gender,hire_date)values(5098,'1990-1-1','ui','jm','M','2014-12-1');
end;
$$;
delimiter ;
call p_insertDemo2;

查看存储过程

show procedure status where db='数据库名';
查看当前数据库下面的存储过程的列表
use 数据库名;
select specific_name from mysql.proc;
查看存储过程的内容
select specific_name,body from mysql.proc;
或者show create procedure 存储过程名字

删除存储过程

drop procedure if exists 存储过程名字;

存储过程修改

alter procedure p_demo1 no sql;
alter procedure p_demo1 comment '注释信息';
7.函数

mysql中函数
1.内置函数(参考手册)
2.自定义函数
use 数据库名;
(1)首先查看是否已经开启了创建函数的功能?
show variables like '%fun%';
(2)如果变量的值为off,那么需要开启
set global log_bin_trust_function_creator =1;
(3)创建函数的语法

create function 函数名(变量1,变量2....)
returns 数据类型
begin
.....执行的程序代码
   return 数据;
end;
delimiter $$;
create function fun_add(a int,b int)
returns int
begin
    return a+b;
end;
$$;
delimiter ;
select fun_add(3,4);

删除函数

drop function if exists fun_add; 
delimiter $$;
create function fun_login(uname varchar(20),upwd varchar(20))
returns varchar(20)
begin
declare rowResult int dafault 0;
select count(*) into rowResult from userinfo where username = uname;
if rowResult = 0 then
    return 'username not exists';
end if;
select count(*) into rowResult from userinfo where username = uname and userpwd = upwd;
if rowResult = 0 then
    return 'userpwd input error';
else 
  return 'login ok';
end if;
end;
$$;
delimiter ;
select * from userinfo;
8.视图

视图
create or replace view v_employees2
as
select * from employees where emp_no % 4 =1;
create or replace view v_employees3
as
select * from employees where emp_no % 4 =2;
create or replace view v_employees4
as
select * from employees where emp_no % 4 =3;
使用视图的好处?
1.简化查询语句
2.可以进行权限控制
3.大数据表分表的时候
视图管理
视图的存放位置?
视图存放在information_schema数据库下的views表里
select * from information_schema.views\G;
或者
use 数据库名;
show tables;
1.查看视图的定义
show table status [from 视图名称][like '匹配'];
show table status from companys like 'v_salaries'\G;
2.删除视图
查看权限
select drop_priv from mysql.user where user='root';
删除视图
drop view[IF EXISTS] view_name;
drop view if exists v_salaries;

3.如果视图包含下述结构中的一种,那么他就是不可更新的:
(1)聚合函数
(2)DISTINCT
(3)GROUP BY
(4)HAVING
(5)UNION或UNION ALL
(6)位于选择列表中的子查询
(7)join
(8)from子句中的不可更新视图
(9)where子句中的子查询
(10)algorithm = temptable(使用临时表总会使视图成为不可更新的)。
4.关于with check option的理解及应用
with check option 可以这么解释:通过视图进行的修改,必须也通过该视图看到修改后的结果。
更新视图的数据,那么必须先满足视图的条件,满足之后才能够更新到基表中。
create or replace view v_salaries
as
select emp_no,salary from salaries where emp_no=1001
with check option;

update v_salaries set salary=2500 where emp_no=1002;
因为不满足视图的条件,所以无法更新到基表。

视图的算法:algorithm=merge合并执行
algorithm=temptable临时表模式
algorithm=undefined系统自动选择两种算法

9.触发器

触发器:是一种特殊的存储过程,它在插入,删除或修改特定表中的数据时触发执行,它比数据库本身标准的功能更精细和更复杂的数据控制能力

它具有这样的特征:
监视地点:一般就是表名
监视事件:update/delete/insert
触发时间:after/before
它不能直接被调用,是由数据库主动去执行。

触发器的语法:

create trigger trigger_name trigger_time trigger_event on 表名 for each row trigger_stmt;
delimiter $$;
create trigger tr_insertEmp after insert 
on employees for each row
begin
    insert salaries values(new.emp_no,0,'2015-5-1');
end;
$$;
create trigger tr_deleteEmp before delete
on employees for each row
begin
 delete from salaries where emp_no = old.emp_no;
end;
$$;
create trigger tr_updateEmp after update 
on employees for each row
begin
 update salaries set from_date = new.hire_date where emp_no=old.emp_no;
end;
$$;
select * from employees where emp_no=1001;
update employees set hire_date = '2015-3-1' where emp_no=1001;
select * from salaries where emp_no = 1001;

触发器的管理

show triggers \G;

select * from information_schema.triggers where trigger_name = 'tr_deleteEmp'\G;

drop trigger tr_deleteEmp;
10.mysql锁

mysql中锁
保证数据并发访问的 一致性
mysql中锁机制比较简单,其最显著的特征是不同的存储引擎支持不同的锁机制。
myisam存储引擎采用的是表级锁,Innnodb存储引擎既支持行级锁,也支持表级锁,但默认情况下是采用行级锁。

mysql三种锁的特性:
表级锁:开销小,加锁快;不会出现死锁;锁定粒度大,发生所冲突的概率最高,并发度最低。
行级锁:开销大,加锁慢;会出现死锁;锁定粒度最小,发生所冲突的概率最低,并发度也最高。
页面锁:开销和加锁介于两者之间;会出现死锁;锁定粒度介于两者之间,并发度一般。

mysql的表级锁有两种模式:表共享读锁和表独占写锁

给表加锁

在数据库sql文件中改storage_engine = MyISAM;
1.加共享读锁
lock table 表名 read

show create table employees;
select * from employees;
lock table employees read;

在另一个客户端窗口,更新数据发现无法更新;
解锁

unlock tables;
show variables like '%table%';
show status like '%table%';
table_locks_waited的值如果太高,说明锁应用的比较多,数据库可能有问题

2.表独占写锁
lock table 表名 write;

use companys;
lock table employees write;
insert into employees values(2098,'1980-1-1');
update employees set gender = 'F' where emp_no = 2098;
delete from employees where emp_no =2098;
select * from employees;
show status like '%table%';
unlock tables;

在锁了一个表后,如果访问其他表会报错,所以要将锁的表解锁后再访问其他的表。共享读锁,允许其他用户读操作,但会阻塞所有写操作;独占写锁,本身进程可以更新操作,不允许其他用户读写操作

如何同时锁两张表?

lock tables employees read,salaries write;
unlock tables;

https://blog.csdn.net/qq_35240226/article/details/82960507
并发插入数据
myisam存储引擎有一个系统变量concurrent_insert,专门用以控制其并发插入的行为,其值分别为0,1或2.
1.当concurrent_insert设置为0时,不允许并发插入。
2.当concurrent_insert设置为1时,如果MyISAM表中没有空间(即表的中间没有被删除的行),MyISAM允许在一个进程读表的同时,另一个进程从表尾插入记录,这也是mysql的默认设置。当释放锁后,另一个进程中的插入操作执行。
3.当concurrent_insert设置为2时,无论MyISAM表中有没有空间,都允许在表尾并发插入记录。

use companys;
show variables like 'concurrent_insert';
set global concurrent_insert =2;
lock table employees read local;#local就是并发插入的意思
insert into employees vallues(5678,'1990-1-1');
unlock tables;

思考:
一个进程请求某个MyISAM表的读锁,同时另一个进程也请求同一个表的写锁?Mysql如何处理呢?
答:写进程先获得锁,即使读请求先到锁等待队列,写请求后到,写锁也会插入到读锁队列之前。mysql认为写请求比读请求更重要。MyISAM不太适合于有大量更新操作和查询操作的原因,因为,大量的更新操作会造成查询操作很难获取读锁,从而可能永远阻塞。

解决方法
1.执行set low_priority_updates=1;使该连接发出的更新请求优先级降低。
其中insert,delete也可以通过此种方法指定。
事务
1.查看数据库下面是否支持事务(Innodb)?
show engines; 事务的单词就是transactions YES/NO
2.查看mysql当前默认的存储引擎?
show variables like '%storage_engine%';
3.查看某张表的存储引擎?
show create table 表名;
4.对于表的存储结构的修改?
建立Innodb表:create table....type=InnoDB; Alter table table_name type=InnoDB;

create datebase bank;
use bank;
create table account(
aid int not null,
accname varchar(20) not null,
accmoney decimal(10,2) not null,
primary key(aid)) engine = innodb default charset = gbk;

insert into account values(1,'A',4000);
insert into account values(1,'B',4000);

select * from account;

start transaction;

commmit;

set autocommit =0;#设置不自动提交

start transaction;
update account set accmoney = accmoney-1000 where aid = 1;
update account set accmoney = accmoney+1000 where aid = 2;
commit;

事务回滚
rollback;

提交并重新开启一个事务
commit and chain;
commit;

还原点
set autocommit=0;
insert into account values(3,‘C’,1000);
savepoint s1;
insert into account values(4,‘D’,2000);
savepoint s2;
insert into account values(5,‘F’,1000);
savepoint s3;
在另外的会话窗口查一下,查不到
rollback to savepoint s2;
commit;
innodb中的锁问题
lock table account write;
insert into account values(7,‘f’,1000);
start transaction #start transaction会造成一个隐含的unlock tables执行。

事务的4个属性:
原子性:一个事务是一个不可分割的工作单位,2步或者N步,要么全成功,要么全失败;
一致性:事务必须是使数据库从一个一致性的状态,到另一个一致性的状态。一致性与原子性是密切相关的。
隔离性:一个事务的执行不会被其他事务干扰,即一个事务内部的操作及使用的数据,其他会话是不可知道的。
持久性:持久性也称永久性,指一个事务一旦提交,它对数据库中数据的改变就应该是永久性的。接下来的其他操作或故障不应该对其有任何影响。

11.慢查询

慢查询:mysql记录下查询超过指定时间的sql语句。

show variables like '%long%';
long_query_time就是指定时间,超过这时间就是慢查询

show status like 'uptime%'#mysql服务器的启动时间
show status like 'com_Select';#当前select语句的运行数量
show status like 'connections'#当前的连接数

set long_query_time = 1;

以安全模式启动mysql服务
mysql.exe --safe-mode --slow-query-log

mysql慢查询的日志
打开my.ini文件,配置如下:
log-slow-queries=D:/MySQL/slow.log
long-query-time = 1
log-queries-not-using-indexes

慢查询时间应该设置为5-10秒

12.索引

https://www.cnblogs.com/-619569179/p/6528896.html
索引:在关系型数据库中,索引是一种与表有关的数据库结构,它可以使对应于表的sql语句执行得更快。索引的作用相当于图书的目录,可以根据目录中的页码快速找到所需的内容。
use companys;
show index from employees;
索引的分类:
1.主键索引
主键对应的列不能为空,一个表中只有一个列可以有主键,主键可以被其他表引用为外键,一般将表中不容易更改的列设置主键,主键其实是一种约束条件,它其实并不属于索引,只是两者查询速度上都有所提高;主键唯一,但唯一索引不唯一。
alter table 表名 add primary key(索引针对的列)
2.唯一索引
(1)唯一的索引所在的列可以为null值。
(2)唯一的索引所在的列不能为空字符串
(3)在一张表中的唯一索引不唯一
创建的语法:
create unique index 索引名称 on 表名(列名)

create unique index uq_depname on department(dept_name);
explain select dept_name from department\G ;

3.普通索引
先创建表,再创建普通索引

create index 索引名称 on 表名(列)

create index norIndex on employees(first_name,last_name);
explain select first_name,last_name from employees\G;

4.全文索引
FULLTEXT索引,用于全文搜索。只有MyISAM表类型支持FULLTEXT索引。FULLTEXT索引只可以从varchark,char,text列中创建。整个列都会被编入索引;不支持对部分列编索引

use companys;
create table articles(
id int unsigned auto_increment not null primary key,
title varchar(200),
body text,
fulltext(title,body))engine=myisam default charset=utf8;

insert into articles(title,body)values
('sjdkdd','sdfdggfgaga'),
('ddffa','afdgg'),
('aaffgfg','afdggggf'),
('afafaff','afaffafa');

explain select * from articles\G #无法查到索引

select * from articles where match(title,body) against('database');
explain select * from articles where match(title,body) against('database')\G;

match()函数对于一个字符串执行资料库内的自然语言搜索。一个资料库库就是1套1个或2个包含在fulltext内的列。搜索字符串作为对against()的参数而被给定。对于表中的每一行,match()返回一个相关值,即搜索字符串和match()表中指定列中该行文字之间的一个相似性度量。

全文停止字:遇到全文停止字,搜索停止;
如果忘记了数据存放的位置,可以在MySQL客户端输入

show global variables like "%datadir%";

索引的原理:
二叉树-->索引文件:效率:log2N
检索10次:2的10次方,1024条记录。
索引带来的开销
查看数据的文件(安装目录下的data目录),会发现有三个文件
.frm:表示表的结构
.myd:表示数据
.myi:表示索引的文件

索引带来的问题:会影响insert,updata,delete的效率
更新非常频繁的字段不适合创建索引。
唯一性比较差的字段不适合创建索引,比如人的性别就只有男和女。

满足以下条件的字段才会创建索引

1.肯定在where条件中经常使用到的。
2.该字段的变化不会太频繁

explain select emp_no from employees\G;
explain select * from employees\G;
explain select emp_no,first_name from employees\G;
可以看出:只有当只有索引的列进行查询时,才会使用索引。只要查询过程中有列没有索引就不会使用索引。

create index index_name on employees(first_name,last_name);
explain select first_name,last_name from employees\G;

通过show profile分析SQL的执行时间
(1)首先查看mysql是否支持show profile
select @@have_profiling;
(2)如果profiling是关闭的,可以通过set语句在session级别开启profiling
set profiling=1;
(3)执行完毕之后,可以通过show profiles语句,查看当前sql的QueryID.
(4)通过show profile for query queryID

use companys;
select @@have_profiling;
set profiling=1;
select count(*) from emp_no>10001;
show profiles;
show profile for query QueryID;

13.表的分析,检查,优化

表的分析,检查,优化
1.定期分析表:
use companys;
analyze table employees;

2.定期检查表(检查表或者视图是否存在)
check table employees\G;
3.定期优化表
optimize table employees\G;
OPTIMIZE TABLE只对MyISAM,BDM和Innodb表起作用
对于MyISAM表,optimize table按如下方式操作:
如果表已经删除或分解了行,则修复表;
如果未对索引页进行分类,则进行分类;
如果表的统计数据没有更新(并且通过对索引进行分类不能实现修复),则进行更新。

[注]:需要注意的是无论是analyze,check,还是optimize在执行期间将对表进行锁定,因此请注意这些操作要在数据库不繁忙的时候执行

获取表的相关信息
show table status\G;

只看一张表的信息
show table status like 'employees'\G;

分区:

当数据量过大时,通常指百万级或千万级数据的时候,这时候需要将一张表的数据划分成几块存储。这主要是借助于满足一个给定where语句的数据可以只保存在一个或多个分区内,这样在查找时就不用查找其他剩余的分区。

分区与分表的区别:
https://blog.csdn.net/fmyzc/article/details/78030262
https://blog.csdn.net/longxingzhiwen/article/details/53931535
分区是数据和索引的存储位置发生变化,数据和索引被分成多块存储,提高了磁盘读写能力,但表还是一张表;
分表是一张表被真正的分成多张表,每张表中数据量变少,增加了存取数据时mysql的并发能力,并且每张表都独立地存取数据。
查看mysql是否支持分区?
show variables like '%partition%';
--如果输入的变量为yes表示mysql是支持分区的。

分区的类型?
range分区:基于属于一个给定连续区间的列值,把多行分配给分区。
create database testpartition;
use testpartition;
create table employees(
id int not null,
fname varchar(30),
lname varchar(30),
hired date not null default '1970-01-01',
separated date not null default '9999-12-31',
job_code int not null,
store_id int not null,
)
partition by range(store_id)(
partition p0 values less than (6),
partition p1 values less than (11),
partition p2 values less than(16),
partition p3 values less than(21),
partition p4 values less than maxvalue
);
insert into employees(id,fname,lname,job_code,store_id)values(1,'aa','bb',1001,10);
insert into employees(id,fname,lname,job_code,store_id)values(1,'aa','bb',1001,21);

show create table employees\G;

list分区:类似于按range分区,区别在于list分区是基于列值匹配一个离散值集合中的某个值来进行选择
假设有20个音像店,分布在4个有经销权的地区,如下表所示:
===============================================
地区 商店ID号
北区 3,5,6,9,17

东区 1,2,10,11,19,20

西区 4,12,13,14,18
中心区 7,8,15,16
=================================================

use testpartition;
create table employees(
id int not null,
fname varchar(30),
lname varchar(30),
hired date not null default '1970-01-01',
separated date not null default '9999-12-31',
job_code int not null,
store_id int not null,
)
partition by list(store_id)(
partition pNorth values in(3,5,6,9,17),
partition pEast values in(1,2,10,11,19,20),
partition pWest values in(4,12,13,14,18),
partition pCentral values in(7,8,15,16)
);
insert into employees(id,fname,lname,job_code,store_id)values(1,'aa','bb',1001,10);
select * from employees;
删除分区
alter table employees drop partition pNorth;
select * from employees;
添加分区
alter table employees add partition(partition pNorth values in(3,5,6,9,17));

create table ty(
id int not null,
deptname varchar(20) not null
)
partition by list columns(deptname)
(partition p1 values in('hr'),
partition p2 values in('soft'));

insert into ty values(1,'hr');

hash分区:基于用户定义的表达式的返回值来进行选择的分区,该表达式使用将要插入到表中的这些行

的列值进行计算。这个函数可以包含mysql中有效的,产生非负整数值的任何表达式。

use testpartition;
create table emp(
id int not null,
fname varchar(30),
lname varchar(30),
hired date not null default '1970-01-01',
separated date not null default '9999-12-31',
job_code int not null,
store_id int not null,
)
partition by hash(store_id)
partitions 4;

insert into employees(id,fname,lname,job_code,store_id)values(1,'aa','bb',1001,10);
key分区:类似于按hash分区,区别在于key分区只支持计算一列或多列,且mysql服务器提供其自身的哈希函数。必须有一列或多列包含整数值。

use testpartition;
create table tk(
col1 int not null,
col2 char(5),
col3 date
)
partition by linear key(col1)
partitions 3;

优化mysqlserver

1.mysql内存管理及优化
打开my.ini配置文件
a.myisam内存优化
myisam存储引擎使用key_buffer缓存索引块,加速myisam索引的读写速度。对于myisam表的数据块,mysql没有特别的缓存机制,完全依赖于操作系统的IO缓存。
(1)key_buffer_size决定myisam索引块缓存区的大小。转化直接影响myisam表的存储效率。对于一般myisam数据库,建议将1/4可用内存分配给key_buffer_size;
key_buffer_size=2G
(2)read_buffer_size
如果如需要经常顺序扫描myisam表,可以通过增大read_buffer_size的值来改善性能。但需要注意的是read_buffer_size每个session独占的,如果默认值设置太大,就会造成内存浪费。
(3)read_rnd_buffer_size
对于需要做排序的myisam表查询,如果有order by子句sql,适当增加read_rnd_buffer_size的值,可以改善此类的sql性能。但需要注意的是read_rnd_buffer_size每个session独占的,如果默认值设置太大,就会造成内存浪费。

b.innodb内存优化
innodb用一块内存区做IO缓存池,该缓存池不仅用来缓存innodb的索引块,而且也用来缓存innodb的数据块。
(1)设置innodb_buffer_pool_size
该变量决定了innodb存储引擎表数据和索引数据的最大缓存区大小。
(2)innodb_log_buffer_size
决定了innodb重做日志缓存的大小,对于可能产生大量更新记录的大事务,增加innodb_log_buffer_size的大小,可以避免innodb在事务提交前就执行不必要的日志写入磁盘操作。

c.调整mysql并发相关的参数
(1)调整max_connections,提高并发连接
(2)调整thread_cache_size,加快连接数据库的速度,mysql会缓存一定数量的客户服务线程已备重用,通过参数thread_cache_size可控制mysql缓存客户服务线程的数量。
(3)innodb_lock_wait_timeout;控制innodb事务等待行锁的时间,对于快速处理的sql语句,可以将行锁等待超时时间调小,以避免事务长时间挂起,对于后台运行的批量处理操作,可以将行锁等待超时时间调大,以避免发生大的回滚操作。

比如前台数据的更新,可以调小;20,30

mysql应用优化

1.访问数据库采用连接池

2.采用缓存减少对于mysql的访问--缓存只有在表不变的条件下,才有作用;如果插入了一条语句,缓存将失效。
a.避免同一数据做重复检索
select name from gy;
select job from gy;
select name,job from gy;

b.使用查询缓存

c.缓存参数的配置
(1)query_cache_type:是否打开缓存
可选项 OFF:关闭 ON:总是打开 DEMAND:只有明确写了SQL_CACHE的查询才会吸入缓存

show variable like 'query_cache_type';

(2)query_cache_size:缓存使用的总内存空间的大小,单位是字节,这个值必须是1024的整数倍

(3)query_cache_min_res_unit:分配内存块的最小单位大小
(4)query_cache_limit:mysql能够缓存的最大结果
(5)query_cache_wlock_invalidate:如果某个数据被锁住,是否仍然从缓存中返回数据,默认是OFF,表示仍然从缓存中返回数据,默认是OFF,表示仍然可以返回

3.使用负载均衡

负载均衡:一个主mysql服务器(Master)与多个从属mysql服务器(Slave)建立复制(replication)连接,主服务器与从属服务器实现一定程度上的数据同步,多个从属服务器存储相同的数据副本,实现数据冗余,提供容错功能。部署开发应用系统时,对数据库操作代码进行优化。
主从配置过程
实现步骤:
1.首先确保主服务器打开二进制日志功能,这样主服务器一旦有数据变化,立即产生二进制日志
2.从服务器也需要开启二进制日志和relay日志功能
这样可以从主服务器读取binlog并产生relaylog
3.在主服务器建立一个从服务器的账号,并授予读binlog的权限
4.指定从服务器对应的主服务器,开启从服务器

本人虚拟机下有两台linuxIP为200 201
1.201做从服务器
2.200mysql作为主服务器
3.保证主从3306端口互通
4.配置主服务器,打开binlog

配置主服务器:打开my.ini配置文件
show master status;
给服务器起一个唯一的id
server-id=201
开启二进制日志,二进制日志的文件为mysql-bin
log-bin=mysql-bin
指定日志格式 mixed/row/statement
binlog-format=row/statement/mixed
statement:2进制记录执行语句,如update。。
row:2进制记录的是磁盘变化
mixed:混合的,有系统根据语句来决定
哪个好?
update age=age+1 where id=3;//语句长而磁盘变化少,易用row
update salary=salary+100; //语句短,但影响上万行,易用statement

重启mysql
show master status;

配置从服务器:打开my.ini文件
server-id=202
log-bin=mysql-bin
binlog-format=mixed
relay-log=mysql-relay

启两台服务器
show slave status;

授权
grant replication client,replication slave on . to repl1@'192.168.1.%' identified by 'rep1';
flush privileges;

在从服务器上输入:
change master to
master_host='192.168.1.201',
master_user='rep1',
master_password='repl',
master_log_file='mysql-bin.000001',
master_log_pos=348;#指针位置

show slave status;
启动
start slave;
若为起来,找错误:
从202看能连上201吗?
telnet 192.168.1.201 3306
ping 192.168.1.201
应该是防火墙的问题

去201关闭防火墙
service iptables stop;

reset slave;
stop slave;
start slave;
show slave status;

mysql监控

1.为什么要有mysql的监控?
随着软件后期的不断升级,mysql的服务器数量越来越多,软硬件故障的发生频率也越来越高。这个时候就需要一套监控系统,当主机发生异常时,此时通过监控系统发现和处理。
2.常见的监控方式的分类
(1)自己写程序或者脚本控制
数据库本身不多,或者数据库很小的时候
a.监控mysql是否提供正常的服务。
mysqladmin -uroot -p123456 -hlocalhost ping
如果结果输出:mysqld is alive
b.获取mysql当前的几个状态值
mysqladmin -uroot -p123456 -hlocalhost status
c.获取数据库当前的连接信息
mysqladmin -uroot -p123456 -hlocalhost processlist
d.获取当前数据库的连接数
mysql -uroot -p123456 -BNe "select host,count(host) from processlist group by host;" information_schema
f.检查,修复,分析,优化MYSQLServer中相关的表
mysqlcheck -u root -p123456 --all-databases

在mysql连接客户端执行以下命令:
a.用于监控mysql使用临时表的量是否过多,是否有临时表过大而不得从内存中换出到磁盘文件上
show status like‘Created_tmp%’;
b.锁定状态:锁定状态包括表锁和行锁两种,我们可以通过系统状态变量获得锁定总次数,锁定造成其他线程等待的次数,以及锁定等待时间信息
show status like ‘%lock%’;
c.innodb_log_waits状态变量直接反应出innodb log buffer空间不足造成等待的次数
show status like ‘innodb_log_waits’;

(2)监控采用商业解决方案

(3)监控开源软件
常用的网络监控工具:
cacti,nagios,zabbix开源的网络监控工具写操作(如update,insert)定向到主服务器,把大量的查询操作(select)定向到从属服务器,实现集群的负载均衡功能。
如果主服务器发生故障,从属服务器将转换角色成为主服务器,使应用系统为终端用户提供不间断的网络服务l,主服务器后恢复运行后,将其转换为从属服务器,存储数据库副本,继续对终端用户提供数据查询检索服务。

mysql管理权限

mysql管理权限
1.作用及意义
mysql权限系统主要用来对连接到数据库的用户进行权限的验证,依此来判断此用户是否是属于合法的用户,如果是合法的用户则赋予相应的数据库权限。
2.查看当前的数据库的用户

use mysql;
select host,user,password form user;

3.mysql权限应用
(1)查看用户的权限
(2)删除用户
(3)修改账号密码
(1)添加账号

grant select on *.* to zy@localhost identified by '123456' with grant option;

grant 权限命令
all privileges是表示所有权限,你也可以使用select,update等权限提到的权限
on 用来指定权限针对哪些库和表。
.中前面的号用来指定数据库名,后面的号用来指定表名。*表示全部所有
to 表示将权限赋予某个用户。
账号@主机地址
identified by 指定用户的登录密码。
with grant option 这个选项表示该用户可以将自己拥有的权限赋予给其他用户。

重新赋予权限:

revoke select on *.* from zy@localhost;

grant select,delete on *.* to zy@localhost identified by '123456' with grant option;
mysql -uzy -hlocalhost -p
use companys;
delete from titles;

(2)查看用户的权限

show grants for '账号'@‘主机ip’
mysql -uroot -p
use mysql;
select host,user,password from user;
show grant for 'root'@'localhost'\G;
show grant for 'zy'@'localhost'\G;
(3)删除用户
drop user 'zy'@localhost;
drop user 'zy'@'%';

(4)修改账号密码
set passsword for 'ty'@'localhost'=password('123');
(5)对账号权限的资源设置
创建一个zi的账号,在companys数据库上具有select权限,在每个小时查询的次数小于5次,最多同时有6个用户进行并发连接。

grant select on companys.* to zi@localhost identified by '123456' with max_queries_per_hour 5 max_user_connections 6;

select user,max_questions,max_connections from user where user='zi';
mysql监控

1.为什么要有mysql的监控?
随着软件后期的不断升级,mysql的服务器数量越来越多,软硬件故障的发生频率也越来越高。这个时候就需要一套监控系统,当主机发生异常时,此时通过监控系统发现和处理。
2.常见的监控方式的分类
(1)自己写程序或者脚本控制
数据库本身不多,或者数据库很小的时候
a.监控mysql是否提供正常的服务。
mysqladmin -uroot -p123456 -hlocalhost ping
如果结果输出:mysqld is alive
b.获取mysql当前的几个状态值
mysqladmin -uroot -p123456 -hlocalhost status
c.获取数据库当前的连接信息
mysqladmin -uroot -p123456 -hlocalhost processlist
d.获取当前数据库的连接数
mysql -uroot -p123456 -BNe "select host,count(host) from processlist group by host;" information_schema
f.检查,修复,分析,优化MYSQLServer中相关的表
mysqlcheck -u root -p123456 --all-databases

在mysql连接客户端执行以下命令:
a.用于监控mysql使用临时表的量是否过多,是否有临时表过大而不得从内存中换出到磁盘文件上
show status like‘Created_tmp%’;
b.锁定状态:锁定状态包括表锁和行锁两种,我们可以通过系统状态变量获得锁定总次数,锁定造成其他线程等待的次数,以及锁定等待时间信息
show status like ‘%lock%’;
c.innodb_log_waits状态变量直接反应出innodb log buffer空间不足造成等待的次数
show status like ‘innodb_log_waits’;

(2)监控采用商业解决方案

(3)监控开源软件
常用的网络监控工具:
cacti,nagios,zabbix开源的网络监控工具

mysql定时维护

1.mysql的定时器
所谓定时器,指的是在某个时间段去执行同样的代码。比如:闹钟,每到指定的时间闹钟就会响。
2.mysql设置定时器
mysql版本从5.1开始支持event的
查看版本 select version();
(1)查看是否开启event,如果是off或者0,表示是关闭的。mysql event功能默认是关闭的。
show variables like '%sche%';
(2)开启event功能

set global event_scheduler =1;

(3)创建定时器
创建事件test_event(其作用:每隔一秒自动调用一段sql语句)

use companys;
首先创建表
drop table if exists eventtable;
create table eventtable
(id int not null auto_increment primary key,
time datetime not null
)engine=innodb default charset=utf8;
创建存储过程
drop procedure if exists p_event_insert;
delimiter $$;
create procedure p_event_insert()
begin
insert into eventtable(time)values(nows());
end
$$
delimiter ;
创建定时器
drop event if exists test_event;
create event test_event
on schedule event 1 second
on completion preserve disable
do call p_event_insert();

[注]:当为on completion preserve的时候,当event到期了,event会被disable,但是该event还是会存在;当on completion not preserve的时候,当event到期的时候,该event会被自动删除掉

开启定时器

alter event test_event on completion preserve enable;
select * from eventtable;

关闭定时器

alter event test_event on completion preserve enable;
select * from eventtable;
mysql备份和还原

1.mysql备份
a.通过使用mysqldump命令备份
mysqldump命令将数据库中的数据备份成一个文本文件。表的结构和表中的数据将存储在生成的文本文件中。
mysqldump命令的工作原理很简单,它先查出需要备份的表的结构,再在文本文件中生成一个create语句。然后,将表中的所有记录转换成一条insert语句。然后通过这些语句,就能够创建表并插入数据。

备份一个数据库,mysqldump基本语法:
mysqldump -u username -p dbname table1 table2...>BackupName.sql
其中:
dbname参数表示数据库的名称;
table1和table2参数表示需要备份的表的名称,为空则整个数据库备份;
BackupName.sql参数表示设计备份文件的名称,文件名前面可以加上一个绝对路径。通常将数据库被分成一个后缀名为sql的文件;
mysqldump -u root -p companys employees titles >D:/BAK.SQL
mysqldump -u root -p companys employees titles >D:/BAK.SQL

备份多个数据库
mysqldump -u root -p --databases dbname1 dbname2 > Backup.sql
mysqldump -u root -p--databases test mysql >D:\backup.sql

备份所有数据库
mysqldump -u username -p --all-databases > BackupName.sql

b.直接复制整个数据库目录

c.使用mysqlhotcopy工具快速备份
主要针对linux系统

2.mysql的还原
a.还原使用mysqldump命令备份的数据库的语法如下:
mysql -u root -p [dbname] < backup.sql

b.还原直接复制目录的备份

通过这种方式还原时,必须保证两个mysql数据库的版本号是相同的。myisam类型的表有效,对于innodb类型的表不可用,innodb表的表空间不能直接复制。

https://www.cnblogs.com/dtting/p/7691202.html

14.多表创建,查询

创建多表,可以描述出表与表之间关系
需求:把网上商城里面用的实体创建成表,并将它们之间建立关系

技术分析:

网上商城的实体:
用户 订单 商品 分类
常用关系:
一对多,用户和订单,分类和商品
多对多,订单和商品,学校和课程
一对一,丈夫和妻子
ER图描述实体与实体之间关系
实体用矩形来表示
属性用椭圆表示
关系用菱形表示
=================
一对多

在开发中,我们将一对多的关系,一方称之为主表,多方称之为多表或者从表,为了表示一对多的关系,一般会在多表的一方添加一个字段,字段名称自定义(建议:主表的名称_id)
字段类型一般和主表的主键的类型保持一致,我们称这个字段为外键

用户和订单
--创建用户表
create table user(
id int primary key auto_increment,
username varchar(20)
);
--创建订单表
create table orders(
id int primary key auto_increment,
totalprice float,
user_id int
);

为了保证数据的有效性和完整性,添加约束(外键约束),
在多表的一方添加外键约束
格式:alter table 从表名称 add foreign key(外键名称) references 主表名称(主键);
例如:alter table orders add foreign key (user_id) references user(id);

添加了外键约束之后有如下特点:
1.主表中不能删除从表中已引用的数据
2.从表中不能添加主表中不存在的数据

在开发中,项目上线的时候才添加外键约束

多对多
商品和订单

多对多,在开发中我们一般引入一张中间表,在中间表中存放两张表的主键,一般还会将这两个主键设置成中间表的联合主键,将多对多拆分成两个一对多。

为了保证数据的有效性和完整性,在中间表上添加两个外键约束。

--创建商品表
create table product(
id int primary key auto_increment,
name varchar(20),
price float
);

--创建中间表
create table orderitem(
oid int,
pid int,
);

--添加外键约束
alter table orderitem add foreign key(oid) references order(id);
alter table orderitem add foreign key(pid) references product(id);
==================================================================
多表查询
笛卡尔积
select user.,order. from user,order;
技术分析:
内连接
格式1:显式的内连接
select a.,b. from a [inner] join b on ab的连接条件
查询用户的订单,没有订单的用户不显示
select user.,order. from user inner join order on user.id=order.user_id;
格式2:隐式的内连接
select a.,b. from a,b where ab的连接条件
查询用户的订单,没有订单的用户不显示
select user.,orders. from user,orders where user.id=orders.user_id;

外连接
左外连接:select a.,b. from a left [outer] join b on 连接条件;
意思:先展示join左边的(a)表的所有数据,根据条件关联查询join右边的表(b),符合条件则展示出来,不符合以null值展示。
查询所有用户的订单详情
select user.,order. from user left join order on user.id=order.user_id;
右外连接:
select a.,b. from b right join a on 连接条件
意思:先展示join右边的表(a)表的所有数据,根据条件关联查询join左边的表(b),符合条件则展示出来,不符合以null值展示。
查询所有用户的订单详情
select orders.,user. from user right join orders on user.id=orders.user_id;

子查询
一个查询依赖于另一个查询
查看用户为张三的订单详情
1.先查询张三的id
select id from user where username = '张三';//3
2.select * from orders where user_id=3;
合并
select * from orders where user_id=(select id from user where username = '张三');

查询订单的价格大于300的所有用户信息
1.先查出订单价格大于300的用户的id
select user_id from orders where price>300;//(3,3,5,null)

  1. select * from user where id in(3,3,5,null);

两个合二为一:
select * from user where id in(select user_id from orders where price>300);

给表起别名
格式: 表 [as] 别名
将查询结果作为一张临时表
select user.,tmp. from user,(select * from orders where price>300) as tmp where user.id=tmp.user_id;
http://www.cnblogs.com/ruoniao/p/6906344.html

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,835评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,598评论 1 295
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,569评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,159评论 0 213
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,533评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,710评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,923评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,674评论 0 203
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,421评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,622评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,115评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,428评论 2 254
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,114评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,097评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,875评论 0 197
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,753评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,649评论 2 271

推荐阅读更多精彩内容