1.编程语言分为过程化语言和非过程化语言,过程化语言完成一个编程任务,需要编程人员明确的指明如何去做,如java,c等。非过程化语言只需要你提出做什么就行了,系统会自动完成你提出的任务。那么SQL语言就是一门非过程语言。
2.SQL功能:DDL(数据定义语言,用来创建修改删除数据库对象,比如表,视图,索引等),DML(数据操纵语言,用于查询添加修改或删除存储在数据库中的数据),DCL(数据控制语言,控制访问数据库中特定对象的用户,控制用户对数据库的访问类型,主要功能是用户访问权限的授予和收回)
3.SQL语言的执行方式有两种,交互式SQL(直接执行SQL语句,由数据库管理系统提供联机交互工具),嵌入式SQL (嵌入到高级语言中)
4. 数据定义类关键词:CREATE TABLE(创建一个数据库表) DROP TABLE(删除一个数据库表),ALTER TABLE(修改一个指定表的表结构),CREATE INDEX(创建一个索引),DROP INDEX(输出一个索引),CREATE PROCEDURE(创建一个存储过程),DROP PROCEDURE(删除一个存储过程)
输出操作类关键词:SELECT(从数据库表中检索数据行),INSERT(向数据库表中添加数据行),UPDATE(跟新指定的数据),DELETE(从数据库表中删除指定的数据行)
权限控制类关键词: GRANT(授予用户访问权限),REVOKE(收回用户访问权限)
事务控制类关键词:COMMIT(提交事务),ROLLBACK(回滚事务)
5.mysql数据库的数据类型
整数类型:TINYINT(一个字节8位存储,最大127),SMALLINT(2个字节,最大32767),MEDIUMINT(3个字节,最大8388607),INT(4个字节,这就很大了),BIGINT(8个字节,超级大),数值类型中有一个bool类型,但是mysql中没有布尔类型,mysql中的bool类型对应的是TINYINT,如果真为1,假为0
实数类型(带有小数部分的数字,MySQL支持精确类型的实数也支持不精确类型的实数):FLOAT(不精确类型,4个字节) DOUBLE(不精确类型,8个字节),DECIMAL(20,2)(精确类型,表示小数点后面有两位,小数点前面18位)
字符串类型(使用最多,占8成之多):VARCHAR(用来保存可变长度的字符串),CHAR(固定长度字符串,固定为创建时候声明的长度,0-255任意值,保存时,不够长度系统能空格补全,检索时候尾部空格会被删除)
当字符串很长的时候会使用TEXT(TINYTEXT,TEXT,MEDIUMTEXT,LONGTEXT,这些只是容纳值的最大长度不一样)和BLOB(TINYBLOB,BLOB,MEDIUMBBLOB,LONGBLOB,和text一样有相同的最大长度),text被看作字符字符串,blob被看作是二进制字符串
日期类型:DATE(3个字节,格式为YYYY-MM-DD,范围从1000-1-1到9999-12-31),TIME(时间,格式HH:MM:SS),YEAR(年份,格式YYYY,范围从1901到2155),DATETIME(精度为秒,保存1000年到9999年,8字节),TIMESTAMP(时间戳类型1970年1月1日,保存范围从1970年到2037年,格林威治标准时间成立,4个字节)
数据类型选择准则,遵循最小原则,简单原则,避免索引列上的NULL
6.基本操作示例:
CREATE TABLE tbl_user ( 创建一个表,三个字段
username VARCHAR(20),
userage INT,
signup_date DATE
);
insert into tbl_user values('shixiaotian ',11,'2013-01-03'); 插入一条记录i
select * from tbl_user; 查询所有记录
select username from tbl_user; 查询username
insert into tbl_user values('xiaoningyuan', 12,'2016-05-09'); 插入一条记录
insert into tbl_user values('xiaoningyuan', 20,'2016-05-09'); 查入一条记录
select signup_date from tbl_user where username='xiaoningyuan' and userage=12; 条件查询
select * from tbl_user where username='xiaoningyuan' and userage=12up; 条件查询
update tbl_user set userage=100 where username='shixiaotian'; 修改满足条件的指定字段的值
delete from tbl_user where userage=12; 删除一条记录
alter table tbl_user add email varchar(50); 给表添加Email字段
alter table tbl_user drop email; 删除Email字段
alter table tbl_user change userage age int; 修改字段名称
alter table tbl_user change age age tinyint; 修改字段数据类型
alter table tbl_user rename user_tbl; 修改表名
alter table testname rename to shixiaotian; 修改表名
rename table shixiaotian to xiaoningyuan; 修改表名
drop table user_tbl; 删除表
7.上面的sql语言都是建立在一个已经有的数据库的基础上的操作,如果没有数据库就需要先创建一个数据库才行。
create database testdb 创建了一个名字是testdb的数据库,名字不能使用纯数字或者是MySQL的关键字,如果你一定要这样,就要用单引号括起来,另外数据库的名字不能重名
create database if not exists testdb 如果名叫testdb的数据库不存在那么就创建一个名叫testdb的数据库
use testdb 这个use命令选择一个数据库,接下来的操作都在这个数据库中完成,如果你想切换到其他数据库 还是使用use命令
重命名数据库的名称现在比较麻烦,rename database这个命令已经不能使用,因为会造成数据的丢失,所以要想修改数据库的名称,需要先将原数据导出之后导入到新数据库中,再将原数据库删除,所以在新建数据库的时候要想好名字
drop database testdb 删除一个数据库,这个命令会将数据库连同内部所有数据都会删除,谨慎使用
show databases; 显示数据库的列表
show tables; 显示这个数据库中的表
show tables from testdb; 假设现在的操作是在数据库a中,那么在当前数据库中显示testdb数据库中的表
describe xiaoningyuan;用来查看表的信息,包括表的字段名称,字段类型,可否为空,是不是主键,默认值,其他信息等。
8.数据库的物理文件的查看,C:\xampp\mysql\data\test_db,这个路径就进入了test_db数据库的物理文件夹中,有三种文件
以opt结尾的文件保存了数据库的配置选项,比如数据库的字符集设置等等
创建一个数据库表之后,一个表对应生成两个文件,一个以frm结尾,记录了表的结构信息,一个以ibd结尾,保存了数据记录和索引信息
9.mysql中的不同的数据类型是保证数据存储的高效性而但是,不同的数据有不同的数据类型相匹配,才能让性能最优,效率更高。
10.alter table xiaoningyuan add age int(6) zerofill; 添加age字段,类型是int,括号中6代表显示6,如果设置的值超了6位那么正常显示,该显示几位就是几位,如果不够那么在数字前用0补齐,如果没有这个zerofill那么就是数字后用空格补齐
对于浮点型,也可以指定显示长度
alter table xiaoningyuan add floattest float(5,2); 添加一个字段,类型是float(5,2),5代表最大位数,2代表小数点后最大两位,多出来的位数四舍五入
insert into xiaoningyuan values(1,'1gh',45,1213.57) 插入1213.57,位数已经超了5位,并且超出最大值,那么实际存储的值就是最大值999.99
insert into xiaoningyuan values(1,'1gh',45,121.577) 插入121.577,位数已经超了5位,但是没有超出最大值,小数位四舍五入,那么实际存储的值就是121.58
对于字符串类型也可以指定长度
create table user( 创建一个user表
myname char(10), char类型指定长度10
myage varchar(10) varchar类型指定长度10
);
insert into user values('123456789***','123456789***'); 插入数据
insert into user values('HELLO','hello'); 插入数据
select * from user; 输出,插入的第一行数据被截断,myname和myage都是只显示前十个字符,和前面的int不一样,不具有伸缩性。
select myage from user where myname='hello'; 可以看到myname存储的HELLO是大写,这里的检索条件是小写,但是依旧可以检索成功
alter table user change myname myname char(10) binary; 如果我们给这个字段加上binary关键字,那么就是存储的是2进制,就可以区分大小写了,再次检索的话就检索不成功,binary是修饰char的,要修饰varchar就用varbinary
11 枚举类型
alter table user add enumtest enum('A','B') binary; 添加一个字段,这个字段的类型是枚举类型,只能选择存储A或者B。
insert into user values('a'),因为类型限制了binary,这里存储的时候并不会存储上A,而是空,如果没有binary限制,小写也是可以的
insert into user values('x') 只能是A或者B
insert into user values('A') 正常
12.set类型,和枚举类型相似,枚举类型的话只能存储枚举值的某一个,但是set可以存储多个
alter table user change settest settest set('A','B','C','D') ;
insert into user values('A,B,C')
13。时间类型
create table datetbl2(
time1 date 创建一个表,添加一个字段date类型
);
insert into datetbl2 values('2012-01-02'),(20150609); 可以 一次插入两个记录,date可以用‘2012-01-02’这中形式,也可以是直接用数字都可以。
select * from datetbl2;
输出
2012-01-02 | |
2012-01-02 | |
2015-06-09 |
alter table datetbl2 add time2 datetime; 再添加一个字段time2,类型是datetime
insert into datetbl2 values('2012-01-02','2012-01-02'); 插入记录同样可以是字符串形式,也可以是数字形式
insert into datetbl2 values('2012-01-02',20120102);
输出结果是
2012-01-02 | |
2012-01-02 | |
2015-06-09 | |
2012-01-02 | 2012-01-02 00:00:00 |
2012-01-02 | 2012-01-02 00:00:00 |
alter table datetbl2 add time3 datetime(2); 再添加一个字段,datetime(2)
insert into datetbl2 values('2012-01-02',20120102,20160905);
输出
2012-01-02 | 2012-01-02 00:00:00 | 2016-09-05 00:00:00.00 |
alter table datetbl2 add time4 timestamp;
alter table datetbl2 add time5 timestamp; 再添加time4和time5 类型是一样的都是timestamp类型,不用插入直接输出结果如下:
2012-01-02 | 2017-11-24 17:09:34 | 0000-00-00 00:00:00 | ||
2012-01-02 | 2017-11-24 17:09:34 | 0000-00-00 00:00:00 | ||
2015-06-09 | 2017-11-24 17:09:34 | 0000-00-00 00:00:00 | ||
2012-01-02 | 2012-01-02 00:00:00 | 2017-11-24 17:09:34 | 0000-00-00 00:00:00 | |
2012-01-02 | 2012-01-02 00:00:00 | 2017-11-24 17:09:34 | 0000-00-00 00:00:00 | |
2012-01-02 | 2012-01-02 00:00:00 | 2016-09-05 00:00:00.00 | 2017-11-24 17:09:34 | 0000-00-00 00:00:00 |
可见time4默认就是系统当前时间,当第一次出现timestamp的时候就会系统默认当前时间,如果第二次出现那么就会赋值为0,如time5输出所示。
14.mysql的算术运算符很简单就是+,-,*,/,%。
select 1+2.0; 结果是2.0
select 1+null; 结果是null,有null参与运算结果就是null
select 'a'+5; 一个字符参与算术运算,那么字符也可以转化成数字,数字在字符前面,那么这个字符串就转化成这个数字,除此之外这个字符串只能是0。输出5
select 'a5'+5; 输出5
select '5a'+5; 输出10
select 2/null; 输出null
select xcol+ycol from num_tbl; 查询xcol列加上ycol列的结果
15.比较运算符=,<>,!=,>,<,<=>,between,in,is null,like,regexp。其中<>,!=都是不等于,<=>用来计算null
select 1=2; 输出1
select 1=null; 输出null
select 1<=>null; 输出0,意思是1不等于null
select null<=>null; 输出1,意思是null等于null
select 'shi'='SHI'; 输出1
select 'shi'='SHI '; 后面的空格会被忽略,输出1
select 'shi'= binary'SHI'; 输出0
select 's'>'x'; 大小的比较,按照字母表顺序,越靠后越大,输出0
select 'aa'<'bb'; 字符串的比较从第一个字符开始比较,第一个字符大的那么这个字符串就大,相等则比较第二个字符,依此类推。输出1
select 'b'<'aac'; 输出0
select 'b' between 'a' and 'c'; 输出1
select 'a' between 'a' and 'c'; 输出1
select 'c' between 'a' and 'c'; 输出 1,可见这个between是包含左右边界的
select 'x' not between 'a' and 'c'; 输出1
select not'x' between 'a' and 'c'; 输出1
select 5 in('a5aa',6,7,8); 这个a5aa被看作0,所以输出0
select 5 in('5aa',6,7,8); 这个5aa被看作5,所以输出1
select 'shixiaotian' like 'shi%'; %是通配符,可以代表一个或者多个字符。输出1
select '**shi**xiao**tian**' like '**%**%**%**'; 输出1
select '**shi**xiao**tian**' like '**%'; 输出1
select '*shixiaotian' like '_shi%'; 一个下划线代表一个字符,输出1
select '**shixiaotian' like '_ _shi%';输出1
select null is null;输出1
select 1 is null;输出0
16.逻辑运算符, 与运算and/&&,或运算or/||,非运算not/!,异或xor(两边逻辑值相反,异或值为真,两边逻辑值相同,异或值为假)
select not 1; 输出0
select ! 1; 输出0
select 2>3 and 3<5; 输出0
select 2>3 && 3<5; 输出0
select 2>3 or 3<5; 输出1
select 2>3 || 3<5; 输出1
select 2>3 XOR 3<5; 输出1
17.位运算,按位与&,按位或|,按位异或^,按位取反~,位左移>>,位右移<<
select 9|4; 9和4按位或,先将两个数字转换成2进制分别是1001和0100,按位或为1101,也就是十进制的13,输出13
select 9<<1; 1001右移一位 10010,转换成十进制为18,输出18
select 9>>1;1001左移一位 100,转换成十进制为4,输出4
select 9^5; 异或运算 ,也就是1001和0101按位异或,结果是1100,十进制的12,输出12
18.基本的数据插入
create table adressbook( 新建一个表,一共是五个字段,如果字段可以为空,那么可以在类型后加上null(什么也不加默认可以为空),如果字段值不许空,类型后加not null
fname varchar(255),
lname varchar(255),
phone varchar(255),
fax varchar(255),
email varchar(255));
insert into adressbook (fname,lname,phone,fax)values('shi','xiao','1346','888888'); 指定插入的字段名称,一一对应的插入
insert into adressbook (fname,fax)values('shi','888888'); 指定字段插入的时候还能随意调换字段的顺序,不一定要按照默认建表时候的字段顺序
insert into adressbook (lname,fname)values('ningyuan','xiao'),('ningyuan','xiao'); 还能一次插入多条数据,用逗号隔开
insert into adressbook values('shi','xiao','1346','888888','1346@136.com'); 不加字段名称的话,需要全部字段数值按顺序插入
19.进阶的数据插入
insert into adressbook set fname='haha'; insert into插入数据还能使用set关键字,那么剩下的字段没有值,默认为null
create table tbl1( 创建一个表tbl1,三个字段,设置不能为空,并且还设置默认值
name varchar(150) not null,
category varchar(50) default 'linux' not null,
pagers smallint default 20 not null);
insert into tbl1 (name)values('shixiaotian'); 插入指定字段,其他字段自动设置成默认值
insert into tbl1 set name='xiaoningyuan'; 同上
create table tbl2( 新建一个表tbl2 ,两个字段,设置tid为主键不能为空自增长
tid tinyint not null auto_increment ,
tname varchar(50) default '' not null,
primary key(tid));
alter table tbl2 add unique (tname); 给tname设置unique属性,也就是tname的值是不能出现重复的
insert into tbl2 (tname)values('shixiaotian'); 插入一条数据,tid自动设置成1
insert into tbl2 (tname)values('xiaoningyuan'); 插入另一条数据,tid自动设置成2,自增长
insert into tbl2 (tname)values('xiaoningyuan'); 插入,因为tname不能重复,所以报错
select * from tbl2;
create table tbl3( 自增长,主键,不能重复等,可以手动设置,也可以直接在创建表的时候写出来
tid tinyint not null auto_increment primary key,
tname varchar(50) default '' not null unique);
20。数据的更新和删除
create table users( 创建一个users表,两个字段
uid tinyint not null primary key auto_increment,
uname varchar(100) unique not null);
insert into users (uname) values('shixiaotian'),('xiaoningyuan'); 插入两个数据
update users set uname='test' where uid=1; 数据的更新
delete from users where uid=1; 数据的删除
数据删除的时候,delete和truncate都能删除整个表的数据但是是有差距的,delete是单纯的表的数据的删除,但是自增长的主键id是删除不了的,所以会出现一种情况就是你一开始插入的两条数据id自动生成为1和2,delete之后数据清空,再次插入的时候id会自动生成为3和4,依此类推。但是truncate删除就不一样了,是将表格整体删除,id也要删除,所以你再插入的时候,id还是会从1开始生成。
mysql防止误删操作,设置了sql_safa_updates这个变量,当这个变量是开启状态的时候,不允许delete 操作删除整个表。
delete from users; 关闭安全状态之后可以直接删除
show variables like '%sql_safe%'; 查看这个变量是不是打开状态,如果是需要修改
set sql_safe_updates=0; 修改为0,关闭这个状态
truncate table users; 删除
select * from users;
21.mysql数学函数
select abs(-9.5); 求绝对值
select ceiling(-9.5); 比当前值大最小整数,-9
select ceiling(9.5); 10
select floor(-9.5); 比当前值小的最大整数 -10
select floor(9.5);9
select greatest(1,20,5,3,69); 求一组数的最大值
select least(1,20,5,3,69); 求一组数的最小值
select mod(12,5); 求12除以5的余数
select pi(); 输出pi的值
select rand(); 输出一个随机数
select round(10.5689); 四舍五入,输出11
select round(10.5689,2); 四舍五入保留两位小数 输出10.57
select truncate(10.5689,0); 截断,不要小数,输出10
select truncate(10.5689,2); 截断,保留两位小数,输出10.56
select sign(-4); 判断正负数,输出-1,代表负数
select sign(4);判断正负数,输出1,代表正数
select sign(0);判断正负数,输出0,代表0
select sin(1); 三角函数
select cos(1);
select tan(1);
select asin(1);反三角函数
select acos(1);
select atan(1);
select degrees(1);弧度变角度
select radians(57);角度变弧度
select power(2,3); 2的三次方
select pow(2,3); 2的三次方
select exp(3); e的三次方
select sqrt(4); 开方
select log(4); 取对数
select ln(4); 取对数
select bin(10); 10的二进制
select oct(10); 10的八进制
select hex(10); 10的十六进制
22.mysql聚合函数
create table num(number int);创建一个表
insert into num values(5),(6),(7),(8),(9),(10); 插入6个数字
select * from num;
select avg(number) from num; 求一个字段平均值
select min(number) from num; 求最小值
select max(number) from num; 求最大值
select sum(number) from num; 求和
select count(number) from num; 求数量,6
select std(number) from num; 标准差
select stddev(number) from num; 标准差
select variance(number) from num; 方差
23.字符串函数
select length('hello'); 求字符串长度
select ucase('hello'); 将字符串中的字符编程大写
select upper('hello');将字符串中的字符编程大写
select lcase('HELLO');将字符串中的字符编程小写
select lower('HELLO');将字符串中的字符编程小写
select strcmp('ok','ko'); 字符串的比较 ,和15中的比较运算符比较的规则是一样的。输出1
select strcmp('ok','ok');输出0
select strcmp('ok','zko');输出-1
select position('ok' in 'ok'); 前一个字符串子后一个字符串中的位置,输出1
select position('ok' in 'hiok'); 输出3
select position('aa' in 'hiok'); aa不存在,那么输出0
select replace('ok' ,'o' ,'m'); ok中的o被替换成了m,输出mk
select insert('hi!china' ,4, 5,'love');前一个字符串从第四个位置开始,连续五个字符,被替换成后一个字符串,输出hi!love
select concat('hi!','love'); 两个字符串连接在一起
select concat_ws('***','hi','love');hi和love用***连接在一起
select left('love',2); 取一个字符串左边两个字符
select right('love',2);取一个字符串右边两个字符
select lpad('love',10,'*');love长4,在左边用*填充够10位
select rpad('love',10,'*');love长4,在右边用*填充够10位
select ltrim(' love ');去掉字符串左边的空格
select rtrim(' love ');去掉字符串右边的空格
select trim(' love ');去掉字符串两边的空格
select substring('hello',2,2);取子串,第二个位置开始的连续两个字符,输出el
select ascii('a');输出小写a的ASCII码97
24.日期函数
select now();2017-11-27 10:55:58 取现在当前时间
select curtime();10:56:47 取现在当前时刻
select curdate();2017-11-27 取现在当前日期
select year(20050206);2005 取日期的年
select year('20050206');
select year('2005-02-06');
select year('2005/02/06');
select month(20050206);2 取日期的月
select month('20050206');
select month('2005-02-06');
select month('2005/02/06');
select monthname(20050206);February,取日期的月的名称
select monthname('20050206');
select monthname('2005-02-06');
select monthname('2005/02/06');
select dayofyear(20050206);37 取日期在这一年中是第几天
select dayofyear('20050206');
select dayofyear('2005-02-06');
select dayofyear('2005/02/06');
select dayofweek(20050206);1 取日期在这个星期中的第几天
select dayofweek('20050206');
select dayofweek('2005-02-06');
select dayofweek('2005/02/06');
select dayname(20050206);Sunday 取这个日期的名称
select dayname('20050206');
select dayname('2005-02-06');
select dayname('2005/02/06');
select week(20050206);6 取这个周是这一年中的第几周
select week('20050206');
select week('2005-02-06');
select week('2005/02/06');
select hour('14:56:12');14 取时间的小时
select minute('14:56:12');56 取分
select second('14:56:12');12 取秒
select date_add(now(),interval 3 year);2020-02-27 11:11:39 当前时间加3年
select date_add(now(),interval 3 month);2018-02-27 11:11:39 当前时间加3月
select date_add(now(),interval 3 day);2017-11-30 11:11:29当前时间加3天
select date_sub(now(),interval 3 month);2017-08-27 11:12:08当前时间减3月
select date_sub(now(),interval 3 day);2017-11-24 11:12:21当前时间减3天
25.数据加密函数
select password('secret') 对字符串进行加密,输出 *14E65567ABDB5135D0CFD9A70B3032C179A49EE7,但是不能用这个结果反向得到原来的字符串,这个加密的不可逆的
select password('SECRET') 这个加密是区分大小写的,得到的结果和上面是不一样的,输出*9D2D1415F6A0D138D693228417BA3ED2B7D06C9E
select encrypt('secret','abc');abc是加密的值的key,这个加密的效果也是不可逆的
insert into users (uname) values(encode('name1','1_key')); 这是一种 可逆的加密,使用key对字符串进行加密
select decode(uname,'1_key') from users; 解密的时候也要使用对应的key进行解密
insert into users (uname) values (aes_encrypt('name1','key')); 这种方式也是可逆的加密,同时加密的强度比上面的方法还要高
select * from users;
select aes_decrypt(uname,'key') from users; 解密
select md5('secret'); md5验证
select sha('secret'); sha加密方式
26.控制流函数
select if(10>20,1,2); 如果10>20成立,那么输出1,不成立就输出2
select ifnull(null,2); 如果第一个参数为空,那么返回第二个参数,此处返回2
select ifnull(1,2); 如果第一个参数不为空,那么返回第一个参数,此处返回1
select nullif(1,2); 如果两个参数不相等,那么返回第一个参数,如果两个相等,那么返回null
select case when 1>2 then 199 else -199 end; 当1>2为真,那么返回199,如果不成立那么返回-199
select case when 0 then 199 else -199 end; 此时0不是真,返回-199
select case when -1 then 199 else -199 end; 此时-1也为真,返回199
select case 'shi' when 'xiao' then 100 当when后面的值和case后面的相等,返回对应的then值
when 'shi' then 200 此处返回200
else 300 end; 如果都不相等则返回300
27.格式化函数
select date_format(now(),'%W %D %M %Y,%r'); 日期的格式化 输出 Monday 27th November 2017,03:11:10 PM,其中W星期几,D几号,M几月,Y哪年,r具体时间
select time_format('100:21:12','%h: %i %p'); 输出04: 21 AM 时间的格式化
select inet_aton('127.0.0.1'); ip地址转换成数字 输出2130706433
select inet_ntoa(2130706433); 数字转换成ip地址
28.类型转换函数
select 1+'99'; mysql 自动将字符串99转化成数字99,输出100
select 1+cast('99' as signed); 用cast 转化成一个有符号的整数 cast能转化的类型还包括binary, char, date ,time , datetime, signed, unsigned
select 'f'='F' ; 默认不区分大小写,输出1
select 'f'=binary 'F' ; 加上binary转化成二进制,输出0
select 'f'=cast('F' as binary); cast强制转化成二进制,输出0
select convert('23',signed); convert也可以强制类型转化,转化的类型和cast一样
select convert('a',binary);
select convert('20050801',date);
select convert('18:12:56',time);
select convert('nn' using utf8); 还能指定字符集类型
29.mysql交叉连接,内连接,外连接。交叉连接加上where条件语句就是内连接,外连接分左连接和右连接。
create table categories ( 创建一个表,两个字段
cid int(11) not null auto_increment primary key,
cname varchar(50) not null unique);
insert into categories (cname) values('sports'),('current'),('business'),('technology'); 插入数据
create table titles ( 创建titles表 4个字段
tid int(11) not null auto_increment primary key,
tname varchar(50) not null unique,
tdate datetime not null,
cid int(11) not null);
insert into titles (tname,tdate,cid) values 插入数据
('today news','20150528',2),
('today sports','20150528',1),
('today business','20150528',3),
('today technology','20150528',4),
('yesterday news','20150527',2),
('yesterday sports','20150527',1),
('yesterday business','20150527',3),
('yesterday technology','20150527',4);
select * from titles; -- 4*8
select * from categories;-- 2*4
select * from categories , titles;-- 6*32 交叉连接 没有where条件语句,用逗号或者cross join连接两个表,生成32条记录
select * from categories cross join titles;-- 6*32
select cname,tname from categories,titles where categories.cid=titles.cid and categories.cname='current'; -- 交叉连接加上条件语句之后成了内连接,内连接的两个表交换左右顺序也是一样的,结果不变
select cname,tname from categories inner join titles where categories.cid=titles.cid and categories.cname='current';内连接可以使用逗号或者使用inner join都行
select cname,tname from titles inner join categories where categories.cid=titles.cid and categories.cname='current';
create table users ( 创建users表
uid int(11) not null primary key,
name varchar(50) not null unique);
insert into users values(100,'sue'),(103,'harry'),(104,'louis'),(107,'sam'),(110,'james'),(111,'mark'),(112,'rita'); 插入数据
create table groups ( 创建groups表
gid int(11) not null primary key,
name varchar(50) not null unique);
insert into groups values(501,'authors'),(502,'actors'),(503,'musicians'),(504,'chefs'); 插入数据
create table users_groups ( 创建users_groups表
uid int(11) not null ,
gid int(11) not null );
insert into users_groups values(11,502),(100,501),(100,502),(100,503),(102,501),(104,502),(107,502),(110,501),(112,501); 插入数据
select * from users;
select * from groups;
select * from users_groups;
select users.name as uname,groups.name as gname from users,groups,users_groups
where users.uid=users_groups.uid and groups.gid=users_groups.gid; -- 内连接
-- 外连接包括左连接和右连接
select * from users left join users_groups on users.uid=users_groups.uid; 左连接就是保留左变表的全部信息,并把右边的表连接进来,两个表的共同字段也会各自保留
select * from users_groups right join groups on users_groups.gid=groups.gid; 右连接就是保留右变表的全部信息,并把左边的表连接进来,两个表的共同字段也会各自保留
select * from users_groups right join groups using(gid); 使用using关键字之后的连接,两个表的共同字段会合并
select * from users_groups left join groups using(gid);
30.内连接,一个表自身和自身的连接
create table menu( 创建一个表,表的第三个字段表示该字段和同一个表的其他字段有父子关系,parent字段就是标识谁是我的父亲。
id int not null auto_increment primary key,
lable varchar(50) not null,
parent int not null);
insert into menu(lable,parent) values('services',0),('company',0),('media',0),('your',0), 插入数据
('for',1),('for',1),
('back',2),('clients',2),('address',2),('jobs',2),('news',2),
('press',3),('kit',3),
('login',4),
('col',15),('cut',15),('boom',15);
select a.lable as lable,b.lable as parent from menu as a ,menu as b where a.parent=b.id; 自己和自己连接,其实也是内连接。
31.联合 其实就是将两个表查询的输出结果,联合在一起一起输出。只要他们查询输出的列数是相同的就行。
create table exchange1 (s varchar(50),p float);
create table exchange2 (s varchar(50),p float);
create table exchange3 (s varchar(50),p float,g int);
create table exchange4 (a varchar(50),b float);
create table exchange5 (a int,b int);
insert into exchange1 values('1a',12.2),('1b',12.2),('1c',12.2),('1d',12.2),('1e',12.2);
insert into exchange2 values('2a',12.2),('2b',12.2),('2c',12.2),('2d',12.2),('2e',12.2);
insert into exchange3 values('3a',12.2,5),('3b',12.2,5),('3c',12.2,5),('3d',12.2,5),('3e',12.2,5);
insert into exchange4 values('4a',12.2),('4b',12.2),('4c',12.2),('4d',12.2),('4e',12.2);
insert into exchange5 values(1,12.2),(2,12.2),(3,12.2),(4,12.2),(5,12.2);
select * from exchange1; 5行数据
select * from exchange2; 5行数据
select * from exchange3;5行数据
select * from exchange4;5行数据
select * from exchange5;5行数据
select s,p from exchange1 union select s,p,g from exchange3; 查询列数不同,出错
select s,p from exchange1 union select s,p from exchange2; 输出10行,两个表的查询结果各5行
select s,p from exchange1 union select a,b from exchange5; 虽然选择查询的列的名称不一样,但是不影响,依旧可以正常输出10行,但是联合成的表的字段是s,p。
还需要注意的一点是,union可以会自动合并相同结果,相同结果会只保留一个。比如union左边的查询得到两个记录分别是(a,1),(b,2),右边的查询得到的记录是(a,2),(b,2),(c2,1),(d,2),那么就会合并两个(b,2)记录为一个,合并的结果称为5条记录。如果不想合并,就需要使用union all。这就是union和union all的区别
32.子查询
create table service( 创建一个service表
sid int not null primary key auto_increment,
sname varchar(50),
sfee int);
insert into service(sname,sfee) values('account',1500),('recruit',500),('recruit',300), 插入数据
('administ',500),('custom',2500),('secuity',600);
create table clientt( 创建一个client表
cid int not null primary key auto_increment,
cname varchar(50)) auto_increment=100; 设置自增长的起始值
insert into clientt(cname) values('jv'),('abc'),('dmw'),('rabit'),('sharp'); 插入数据
select *from clientt;
create table branch( 创建一个branch表
bid int not null primary key ,
cid int,
bdesc varchar(50),
bloc varchar(10));
insert into branch values(1012,102,'account','ny'),(1041,104,'be','ma'),(1042,104,'bw','ca'), 插入数据
(1011,101,'ch','ca'),(1013,101,'cd','ka'),(1101,110,'ho','ca'),
(1031,103,'n','me'),(1032,103,'ne','ct'),(1033,103,'nw','ny');
select *from branch;
create table branch_service( 创建一个branch_service表
bid int ,
sid int);
insert into branch_service values(1011,1),(1011,2),(1011,3),(1011,4),(1012,1),(1013,5),(1031,2), 插入数据
(1031,3),(1031,4),(1032,3),(1033,4),(1041,1),(1041,4),(1042,1),(1042,4),(1101,1);
select *from branch_service;
select bdesc from branch,clientt where branch.cid=clientt.cid and clientt.cname='rabit'; 使用内连接的方式,查询client名为rabit对应的branch 中的bdesc
select bdesc from branch where cid=(select cid from clientt where cname='rabit'); 使用子查询的方式,先查询client对应的cid,然后通过cid查询bdesc
虽然子查询的方式效率相对于内连接方式差,但是子查询的方式更加的明了,简单直观。
select *from branch; 查询整个表
select cid from branch ; 提取cid这个列,cid会有重复
select cid from branch group by cid ; group by对cid进行分组,分组之后就没有重复的cid了
select cid ,count(cid) from branch group by cid ; 分组之后cid被合并,进行count计算,计算每个cid重复出现的次数
select cid ,bloc from branch group by cid having bloc='ny' ; 分组之后,得到分组结果,结果中查询bloc=ny的结果
select cid,count(bid) as ct from branch group by cid order by ct desc; 在branch表中对cid进行分组,在每一个组中统计bid的个数,然后使用order by进行排序,默认排序是升序,使用desc之后为降序排列
select cid,count(bid) from branch group by cid having count(bid)=2;对cid进行分组之后,查看每一个分组,找出分组中bid个数为2的cid。
select * from clientt where exists (select bid from branch_service group by bid having count(bid)>=4); 这个语句的目标就是有条件的执行select * from clientt,只有在exsits后面的查询语句有查询结果的时候才会执行select * from clientt,如果exsits后面的查询语句不能有结果,那么不执行select * from clientt,那么整个语句的查询结果就是null
select sname from service where sid in (select sid from branch_service where bid=1031); in后面的语句是select sid from branch_service where bid=1031,这个语句的查询结果有三个,也就是sid有三个,那么这个语句就是将三个查询整合在一起了。in就起到了包含的意思,sid不是一个,sid在一个范围里面。
再说一下having和where的区别,having是将数据分组之后,执行having条件,在分组的数据中再筛选,从而得到最终查询结果。where则是,以where后面的条件进行查询,直接得到最终查询结果。
select bid,count(sid) as total from branch_service group by bid; 对bid进行分组,统计每组bid中的sid的个数
select avg(s.total) from(select bid,count(sid) as total from branch_service group by bid)as s; 上面求出各组bid对应的sid的个数之后对个数进行求均值
update service set sfee=sfee*1.5 where sid in(select sid from branch_service group by sid having count(bid)>=3); in中的语句是select sid from branch_service group by sid having count(bid)>=3,这是出巡对应的bid的个数大于等于3的sid,可以求出多个sid。那么原查询语句中where条件中sid in()就可以有多个sid。
33.事务(transaction),作为一个单独单元的一个或者多个sql语句组成,这个单元中的每个sql语句是相互依赖的,而且单元作为一个整体是不可分割的。如果单元中的每一个语句不能成功的完成,整个单元就会回滚,所有影响到的数据库将返回事务开始以前的状态因此只有事务中所有语句都被成功执行才能说这个事务被成功执行了。举一个形象的例子,一个银行账户A转账给账户B,A减去五百,B加上五百,如果A减去操作成功,但是B加上操作失败了,那么就相当于这次转账操作失败了,但是A已经损失了五百,这是没有事务的结果,在实际中是不允许的,实际中有事务来保证这个转账的操作,转账这个事务包括 两个动作,A减去动作和B加上动作,执行顺序也是先减去后加上,并且两个动作都执行成功才能算事务执行成功,如果其中一个动作不成功,就算事务执行不成功,那么事务中的每个动作的执行结果都要被取消,相当于这次事务压根没有进行。
事务和ACID属性:原子性(每个事务都是一个不可分割的单元),一致性(不管事务成功还是失败,系统状态必须一致,要么都是成功的结果,要么都是失败的结果),孤立性(事务在自己的空间发生,和其他发生在系统中的事务隔离。而且事务的结果只有在完全被执行时才能看到),持久性(即使系统崩溃,一个提交的事务任然在坚持)
34.通过show engines;可以查看数据库的引擎,不同的引擎支持不同的工作,mysql中默认的引擎是InnoDB,这个引擎可以支持事务操作。我们在创建一个表的时候可以指定引擎的类型,如果不指定,默认的就是innoDB。
create table test ( 创建一个表指定引擎是innodb,不指定的时候默认也是这个
sid int,
version int) engine=innodb;
select *from test;
start transaction; 开启一个事务,有三种方式,start transaction,begin,begin work。
insert into test values(1,1); 事务的内容是插入一个数据,当然事务的内容可以是多条sql语句
commit; 当使用commit的时候,事务提交,事务中的操作全部有效保存在数据库中,同时这个事务的生命周期正式结束
rollback; 当使用rollback的时候,事务回滚,事务中的操作全部取消,同时这个事务的生命周期正式结束
35.在mysql中,事务的提交一般是自动提交,除非你显示的开辟 了一个事务,那么你需要手动的提交,如果不是这样,正常的一些sql语句都是自动提交
select @@autocommit; 查看自动提交属性,默认是1,也就是说,自动提交是默认打开的
set autocommit=0,可以设置默认提交属性为0,那么就关闭了,这样的话,执行一条sql语句的时候,结果不会有效保存在数据库中,除非手动commt
36.事务的隔离级别,四个级别,从高到低一次是serializable(序列化,安全性最高,但是性能就会降低),repeatable read(可重复读 ),read committed(提交可读),read uncommitted(不提交可读,安全性最差,但是性能相对好点)
select @@global.tx_isolation,@@session.tx_isolation; 查看全局隔离级别和session隔离级别,mysql默认的全局和session隔离级别都是repeatable read
set session transaction isolation level serializable; 修改设置session隔离级别
set session transaction isolation level REPEATABLE READ;
set session transaction isolation level READ committed;
set session transaction isolation level READ uncommitted;
serializable:现在开启两个连接(两个session,a和b),将session a的事务隔离级别设置成serializable,在两个session中都分别开启事务,开启之后,在session a中对一个表进行一个操作,那么这个事务就获取了对表的绝对操作权限(此时别的事务只能对这个表进行读操作,写操作将会被拒绝,直到session a中的事务提交),如果session b中的事务想查询表,那么可以允许,如果想添加修改等那么被拒绝,只有session a中的事务结束才可以。
repeatable read: 能保证重复读的一致性,但是会导致幻读,具体如下:打开两个session,并各自开启一个事务,mysql默认的事务隔离等级就是repeatable read。数据库中有一个表,初始的记录只有三行,在session a 的事务中查询这个表,出现三行记录,此时在session b中的事务中添加一行记录,session a中查询还是三行,session b事务提交了,现在的表实际的行数已经是四行了,但是此时session a事务中查询还是三行记录,这就是所谓的保证了重复度的一致性。但是, 如果session a的事务中,对表的一条记录的某个值进行一次修改,修改之后再查询,那么就成了四行了,之前session b中添加的那个记录就出现了,那么,同一个事务的两次查询出现了不一样的结果,这就是幻读。
read committed:只要提交了,就能读,会导致多次的查询结果出现不一致。在这种隔离级别之下,一个事务中的查询会出现查询结果a,但是当另外一个事务中对数据表进行了修改,并提交事务之后,再次同样的查询,可能会出现查询结果b,a和b是完全不一样的。那么,这种数据的不安全性叫做不可重复读。
read uncommitted:只要修改了,就能读,会导致脏读的现象。在session a中修改了数据库表,但是并没有提交,但是在session b就可以直接查询到session a中修改后的结果b,这样就会导致一个问题就是,如果session a现在不想要那个对数据库表的操作了,执行了rollback。那么session b再次读的时候就会得到原本的结果a,那么两次查询的结果不一样,这就是脏读。
37.因为支持事务的数据库在事务隔离方面的工作比较复杂,所以会导致这种数据库的性能有所下降,但是这种事务隔离的安全性给我们带来了很好的安全保障,因此需要在使用上注意,要可以的去提高性能:尽量使用小事务(不要一个事务中包含大量的操作),选择合适的隔离级别(对于安全性不是很高的数据,可以选择安全级别低点的事务隔离),保证事务开始前的一切操作都是可行的(如果事务开始之前的操作就是有问题的,那么会导致事务操作不成功),避免死锁(避免两个事务之间因为争夺对方的资源而造成锁)
38.一些不支持事务的存储引擎为了做到达到事务的效果,实现了对表的锁定,包括都锁定和写锁定。读锁定的时候,所有的session都是只能读,不能写。写锁定的时候,只有当前session能读能写,别的读写都是不允许的。
lock table test read; 给表加读锁定锁
lock table branch write; 给表加写锁定表
unlock tables ;解锁
39.数据库管理的基本任务:只知道数据库的创建,添加数据,查询等是不够的,还需要了解数据库的管理问题,比如管理安全,分配用户权限和备份数据等。基本任务包括运行时间,数据备份,安全和访问控制,性能优化,使用日志排错和统计
40.mysql授权表,和权限相关的表在mysql数据库中,这是一个系统数据库,具体如下:
show databases; 查看所有的数据库,里面有mysql数据库
show tables from mysql; -- 系统数据库,授权表就在这里面
use mysql; 设置当前数据库为mysql
select * from user; 这五个表就是授权相关的表
select * from db;
select * from host;
select * from tables_priv; 表的权限
select * from columns_priv; 列的权限
41.权限授予的具体操作,使用关键字grant,具体操作是grant+权限类型+on+数据库或表(赋予权限在那个数据库或表上)+授予的人@主机号+identified by +密码+with grant option(有这个的话说明被授予权限的人也能给其他用户授予权限,没有的话说明这个用户不能给别人授予权限)
grant all privileges on *.* to meiko@localhost identified by '123465' with grant option; 授予所有权限,在任何数据库的任何表上 给meiko,同时meiko还能给别人授予权限,在这里on 后面的*.*中的第一个*代表任何数据库,后一个*代表任何表
grant select,insert,delete on testdb.* to xiaoningyuan@localhost identified by '123465'; 授予选择,插入,删除权限在testdb上的任何表给xiaoningyuan,但是他不能给别人授予权限。
revoke delete on testdb.* from xiaoningyuan@localhost; 撤回权限
drop user xiaoningyuan@localhost; 删除角色用户
flush privileges; 对权限进行授予修改之后要刷新权限,让权限生效,让权限可以使用
show grants for root@localhost; 显示用户的权限
show grants for meiko@localhost;
42.补充一个modify关键字,修改的意思
create table aaaa(a int not null,b int not null,c int not null);创建一个表,三个简单的字段
insert into aaaa values(5,2,2); 插入一条数据
select * from aaaa;
alter table aaaa change b b char; 修改列名可以用change关键字 还能用modify关键字,modify相对简单
alter table aaaa modify c char;
alter table aaaa modify b int first ; 修改列的位置,b放在第一列,first关键字,可以把一个列放在第一列
alter table aaaa modify b char after c ; 修改列的位置,b放在c列的后面,after关键字,可以把一个列放在第另一列的后面
describe aaaa;
alter table aaaa add d int not null first; 插入一个列的时候也可以指定一个列的插入位置,首位或者插在一个已有列的后面,这一句是插在首位
alter table aaaa add e int not null after c; 插在c后面
43 索引相关内容:
索引的概念:索引是一种特殊的文件(InnoDB数据表上的索引是表空间的一个组成部分),它们包含着对数据表里所有记录的引用指针。更通俗的说,数据库索引好比是一本书前面的目录,能加快数据库的查询速度。在没有索引的情况下,数据库会遍历全部数据后选择符合条件的;而有了相应的索引之后,数据库会直接在索引中查找符合条件的选项。如果我们把SQL语句换成“SELECT * FROM article WHERE id=2000000”,那么你是希望数据库按照顺序读取完200万行数据以后给你结果还是直接在索引中定位呢?答案肯定是索引。
索引分为聚簇索引和非聚簇索引两种,聚簇索引是按照数据存放的物理位置为顺序的,而非聚簇索引就不一样了;聚簇索引能提高多行检索的速度,而非聚簇索引对于单行的检索很快。
建立索引的原则:
1.最左前缀匹配原则,非常重要的原则,mysql会一直向右匹配直到遇到范围查询(>、<、between、like)就停止匹配,比如a = 1 and b = 2 and c > 3 and d = 4 如果建立(a,b,c,d)顺序的索引,d是用不到索引的,如果建立(a,b,d,c)的索引则都可以用到,a,b,d的顺序可以任意调整。
2.=和in可以乱序,比如a = 1 and b = 2 and c = 3 建立(a,b,c)索引可以任意顺序,mysql的查询优化器会帮你优化成索引可以识别的形式
3.尽量选择区分度高的列作为索引,区分度的公式是count(distinct col)/count(*),表示字段不重复的比例,比例越大我们扫描的记录数越少,唯一键的区分度是1,而一些状态、性别字段可能在大数据面前区分度就是0,那可能有人会问,这个比例有什么经验值吗?使用场景不同,这个值也很难确定,一般需要join的字段我们都要求是0.1以上,即平均1条扫描10条记录
4.索引列不能参与计算,保持列“干净”,比如from_unixtime(create_time) = ’2014-05-29’就不能使用到索引,原因很简单,b+树中存的都是数据表中的字段值,但进行检索时,需要把所有元素都应用函数才能比较,显然成本太大。所以语句应该写成create_time = unix_timestamp(’2014-05-29’);
5.尽量的扩展索引,不要新建索引。比如表中已经有a的索引,现在要加(a,b)的索引,那么只需要修改原来的索引即可
索引的类型:
普通索引(没有任何限制,是最基本的索引),
组合索引(最左前缀)(也属于是普通索引,针对title和time建立一个组合索引:ALTER TABLE article ADD INDEX index_titme_time (title(50),time(10))。建立这样的组合索引,其实是相当于分别建立了下面两组组合索引:
–title,time
–title
为什么没有time这样的组合索引呢?这是因为MySQL组合索引“最左前缀”的结果。简单的理解就是只从最左面的开始组合。并不是只要包含这两列的查询都会用到该组合索引)
唯一索引(与普通索引类似,不同的就是:索引列的值必须唯一,但允许有空值。如果是组合索引,则列值的组合必须唯一,创建方法和普通索引类似)
主键索引(它是一种特殊的唯一索引,不允许有空值。在建表的时候同时创建的主键即为主键索引,无需命名,一个表只能有一个主键。主键索引同时可是唯一索引或者全文索引,但唯一索引或全文索引不能共存在同一索引)
全文索引(对于较大的数据集,将你的资料输入一个没有FULLTEXT索引的表中,然后创建索引,其速度比把资料输入现有FULLTEXT索引的速度更为快。不过切记对于大容量的数据表,生成全文索引是一个非常消耗时间非常消耗硬盘空间的做法。)
使用索引注意点:
1.过多的使用索引将会造成滥用。因此索引也会有它的缺点:虽然索引大大提高了查询速度,同时却会降低更新表的速度,如对表进行INSERT、UPDATE和DELETE。因为更新表时,MySQL不仅要保存数据,还要保存一下索引文件。建立索引会占用磁盘空间的索引文件。一般情况这个问题不太严重,但如果你在一个大表上创建了多种组合索引,索引文件的会膨胀很快。索引只是提高效率的一个因素,如果你的MySQL有大数据量的表,就需要花时间研究建立最优秀的索引,或优化查询语句。
2.索引不会包含有NULL值的列,只要列中包含有NULL值都将不会被包含在索引中,复合索引中只要有一列含有NULL值,那么这一列对于此复合索引就是无效的。所以我们在数据库设计时不要让字段的默认值为NULL。
3.使用短索引对串列进行索引,如果可能应该指定一个前缀长度。例如,如果有一个CHAR(255)的列,如果在前10个或20个字符内,多数值是惟一的,那么就不要对整个列进行索引。短索引不仅可以提高查询速度而且可以节省磁盘空间和I/O操作。
3.索引列排序,MySQL查询只使用一个索引,因此如果where子句中已经使用了索引的话,那么order by中的列是不会使用索引的。因此数据库默认排序可以符合要求的情况下不要使用排序操作;尽量不要包含多个列的排序,如果需要最好给这些列创建复合索引。
4.like语句,一般情况下不鼓励使用like操作,如果非使用不可,如何使用也是一个问题。like “%aaa%” 不会使用索引,而like “aaa%”可以使用索引。
5.不要在列上进行运算例如:select * from users where YEAR(adddate)<2007,将在每个行上进行运算,这将导致索引失效而进行全表扫描,因此我们可以改成:select * from users where adddate<’2007-01-01′。关于这一点可以围观:一个单引号引发的MYSQL性能损失。
索引的存储类型目前只有两种(btree和hash),具体和存储引擎模式相关:
MyISAM btree
InnoDB btree
MEMORY/Heap hash,btree
hash 索引结构的特殊性,其检索效率非常高,索引的检索可以一次定位,不像btree(B-Tree)索引需要从根节点到枝节点,最后才能访问到页节点这样多次的IO访问,所以 hash 索引的查询效率要远高于 btree(B-Tree) 索引。
B-Tree 索引是 MySQL 数据库中使用最为频繁的索引类型,除了 Archive 存储引擎之外的其他所有的存储引擎都支持 B-Tree 索引。不仅仅在 MySQL 中是如此,实际上在其他的很多数据库管理系统中B-Tree 索引也同样是作为最主要的索引类型,这主要是因为 B-Tree 索引的存储结构在数据库的数据检 索中有非常优异的表现。
一般来说, MySQL 中的 B-Tree 索引的物理文件大多都是以 Balance Tree 的结构来存储的,也就是所有实际需要的数据都存放于 Tree 的 Leaf Node ,而且到任何一个 Leaf Node 的最短路径的长度都是完全相同的,所以我们大家都称之为 B-Tree 索引当然,可能各种数据库(或 MySQL 的各种存储引擎)在存放自己的 B-Tree 索引的时候会对存储结构稍作改造。
如 Innodb 存储引擎的 B-Tree 索引实际使用的存储结构实际上是 B+Tree ,也就是在 B-Tree 数据结构的基础上做了很小的改造,在每一个Leaf Node 上面出了存放索引键的相关信息之外,还存储了指向与该 Leaf Node 相邻的后一个 LeafNode 的指针信息,这主要是为了加快检索多个相邻 Leaf Node 的效率考虑。
在 Innodb 存储引擎中,存在两种不同形式的索引,一种是 Cluster 形式的主键索引( Primary Key ),另外一种则是和其他存储引擎(如 MyISAM 存储引擎)存放形式基本相同的普通 B-Tree 索引,这种索引在 Innodb 存储引擎中被称为 Secondary Index 。
在 Innodb 中如果通过主键来访问数据效率是非常高的,而如果是通过 Secondary Index 来访问数据的话, Innodb 首先通过 Secondary Index 的相关信息,通过相应的索引键检索到 Leaf Node之后,需要再通过 Leaf Node 中存放的主键值再通过主键索引来获取相应的数据行。
索引的建立基本就是三种方式,一个是直接建表的时候建立索引,另一个是修改表的形式建立索引,最后一个是create创建索引
-- 普通索引
alter table branch add index bindex (cid) ; 给cid属性添加索引
create index bbindex on branch (bdesc(20),bloc(10)); 添加一个组合索引
create table cindex (
a int,
b varchar(20),
index bindex (b(10))); 创建表的时候就添加索引
drop index bbindex on branch; 删除索引
-- 唯一索引,添加了一个unique
alter table branch add unique index bindex (cid) ;
create unique index bbindex on branch (bdesc(20),bloc(10));
create table cindex (
a int,
b varchar(20),
unique index bindex (b(10)));
drop index bindex on cindex;
-- 主键索引
create table cindex (
a int,
b varchar(20),
primary key (a)); -- 直接指定主键索引,设置主键
alter table cindex add primary key (a);
alter table cindex add index bindex (b);
--全文索引,创建方式都是三种,不写了
create fulltext index findex on cindex(b(5));
-- 索引的修改并没有直接的语法支持,需要先删除当前索引之后再重新建立,达到修改的目的。
-- 创建一个索引,前缀长度可以加也可以不加,即索引在该列从最左字符开始存储的信息长度,单位字节如果是CHAR,VARCHAR类型,前缀长度可以小于字段实际长度;如果是BLOB和TEXT类型,必须指定 前缀长度
44.mysql视图
视图即是虚拟表,也称为派生表,因为它们的内容都派生自其它表的查询结果。虽然视图看起来感觉和基本表一样,但是它们不是基本表。基本表的内容是持久的,而视图的内容是在使用过程中动态产生的。方便操作,特别是查询操作,减少复杂的SQL语句,增强可读性;
下面创建几个表用来视图的操作
create table stu1( 创建一个学生表
sid int auto_increment primary key,
sname varchar(50) not null,
class int);
select * from stu1;
insert into stu1(sname,class) values('shi',15),('xiao',14),('zhang',13); 插入数据
create table couse1( 创建一个课程表
cid int primary key auto_increment,
cname varchar(50) not null);
select * from couse1;
insert into couse1(cname) values('java'),('c'),('math'); 插入数据
create table sc1( 创建一个学生课程信息表
sid int,
cid int,
score int);
insert into sc1 values(1,1,99),(1,2,99),(1,3,99), 插入数据
(2,1,88),(2,2,88),(2,3,88),
(3,1,77),(3,2,77),(3,3,77);
select * from sc1;
create view view1 as ( 创建一个视图,包含学生姓名,课程名称,成绩,分别来自三个表
select stu1.sname as name,couse1.cname as couse,sc1.score as scroe
from ((stu1 left join sc1 on(stu1.sid=sc1.sid))left join couse1 on (sc1.cid=couse1.cid)));
select * from view1;
对视图的数据进行操作的时候是有条件的,不能在一张由多张关联表连接而成的视图上做同时修改两张表的操作,要想修改,必须视图与表是一对一关系情况,如果没有其它约束(如视图中没有的字段,在基本表中是必填字段情况),是可以进行增删改数据操作;视图与表是一对多关系情况:如果只修改一张表的数据,且没有其它约束(如视图中没有的字段,在基本表中是必填字段情况),是可以进行改数据操作;虽然视图有时候是可以跟新的,但是最好是直接作为查询来使用。
update view1 set scroe=100 where name='shi' and couse='c'; 对视图进行修改操作,这个句子其实只是修改了一个表的内容所以是可以允许的
insert into view1 values('aaa','python',100),插入语句,但是修改的是多个表,不是一对一,是不允许的。
如果我们新建立一个视图
create view view2 as (select cname from couse),这个视图是课程表的一部分,那么视图和表之间的关系就是一对一的,那么可以进行增删改查操作,都是可以的
45.创建表的时候建立外键和联合主键。
create table ttt(
sid int,
cid int,
score int,
foreign key (sid) references stu1 (sid), -- 外键
foreign key (cid) references couse1(cid), -- 外键
primary key (sid,cid)); -- 联合主键
差不多了,就这么多把,不够细致,不够全面,但是基本的东西都有,随用岁学!