常用SQL笔记

SQL笔记

数据库相关概念

1.DB:数据库,保存一组有组织的数据的容器

2.DBMS:数据库管理系统,又称为数据库软件(产品),用于管理DB中的数据

3.SQL:结构化查询语言,用于和DBMS通信的语言

基本SQL操作

1.操作数据库

-- 查询数据库
show databases;
-- 创建数据库
create database newDatabase;
-- 删除数据库
drop database newDatabase;

2.操作数据表

-- 选择指定数据库
use testDB;	
-- 查询当前数据库下的全部数据表
show tables;
-- 创建表
create table tb_user(
	id int(11) not null auto_increment primary key,
	name varchar(255) not null,
	age int(11)
);
-- 创建表,存在则不会创建
create table if not exists tb_user2(
	id int(11) not null auto_increment primary key,
	name varchar(255) not null,
	age int(11)
);

-- 使用旧表创建新表(只复制表的结构,不复制表的数据)
create table newTable like tb_user;
-- 使用旧表(部分列)创建新的表(既复制表的结构又复制表的数据)
create table newTables as select id,name,age,matching from tb_user;
-- 使用就表创建新表(全部列,既复制表的结构又复制表的数据)
create table newTable1 as select * from tb_user;

-- 查询表的结构
desc testAlter;
show columns from testAlter;

-- 将A表的查询结果插入到B表中。
insert into tb_new_user select * from tb_user;

-- 清除表中的数据
-- 注意:删除表的所有行,但表的结构、列、约束、索引等不会被删除;不能用于有外建约束引用的表
truncate table tb_new_user;

-- 删除表如果存在
drop table if exists tb_new_user2;

-- 对数据表的列进行操作
-- 对表的重命名
alter table tb_user1 rename [TO] tb_new_user1;

-- 增加列
alter table tb_user add new_column varchar(255) comment '这是新增列';
alter table tb_user add column new_column varchar(255) comment '这是新增列';
alter table tb_user add column new_column varchar(255) not null comment '这是新增的非空列';
alter table tb_user add column new_column int(11) not null default 0 comment '这是新增非空默认为0的列';

-- 删除列
alter table tb_user drop column newColumn;
alter table tb_user drop newColumn;

-- 修改列
alter table tb_user change column new_column newColumn varchar(256) not null ;
alter table tb_user change column new_column newColumn int(11) not null default 0 comment '修改列名';

3.select语句

1.普通查询
-- 查询整张表的所有列
select * from tb_user;

-- 查询指定列
select id, name from tb_user;
2.distinct
-- 使用 distinict语句 (获得不同的值)(查询结果的所有列与别的记录)
select distinct name,age from tb_user;
select distinct name from tb_user;
3.where
-- where 子句  筛选
select * from tb_user where id = 1;
4.order by
-- 按id降序
select * from tb_user order by id desc;
-- 按id升序
select * from tb_user order by id asc;
-- 多条件排序
select * from tb_user order by name,age asc;
5.and , or
-- and 子句
select * from tb_user where name = 'yanghao' and age = 21;
-- or 子句
select * from tb_user where name = 'yanghao1' or age = 21;
6.like
-- like 子句 模糊查询
select * from tb_user where name like '%hao';
select * from tb_user where name like 'yang%';
select * from tb_user where name like '%yang%';

-- % - 百分号表示零个,一个或多个字符
-- _ - 下划线表示单个字符
select * from tb_user where name like 'yanghao_';
7.between and
-- BETWEEN运算符是包含性的:包括开始和结束值。
-- between and
select * from tb_user where id between 1 and 2;
select * from tb_user where id not between 1 and 2;
8.null
-- is null ,is not null 
select * from tb_user where matching is null;
select * from tb_user where matching is not null;
9.limit
-- limit 
select * from tb_user limit 2;
-- 去下标为1的开始,2条。注意与between and 进行区分
select * from tb_user limit 1,2;
10.in
--  IN 运算符
select * from tb_user where id in (1,2,3);
select * from tb_user where name in ('yanghao', 'lisi');

-- 利用子查询的结果作为in的元素
SELECT
	* 
FROM
	tb_user 
WHERE
	NAME IN ( SELECT NAME FROM tb_user WHERE id IN ( 2, 3 ) );
	
select * from tb_user;
11.case
-- switch(case) 语句 
SELECT
	id,
	NAME,
	age,
	(CASE matching WHEN 0 THEN '零' WHEN 1 THEN '壹' WHEN 2 THEN '贰' end)  AS number
FROM
	tb_user;
12.if
select if(true,'yes','no') as status;

-- if 函数
select id,name,age,matching , if(sex = 'w','女','男') as '姓别' from tb_user;
12.group by
-- group by
select sex, count(sex) count from tb_user group by sex;
select name, count(*) count from tb_user group by name;

select name,age,count(*) count from tb_user group by name,age;
13.union
-- 并集,将多个结果连接起来
select * from tb_user where name like '%hao%'
union
select * from tb_user where age = 18;

4.insert语句

-- insert插入语句
-- (两种,一种是插入全部字段,则可以简化为如下)
insert into tb_user values(6,'zhangsan',18,1,1);
insert into tb_user (name,age,matching, newColumn) values( 'zhangsan',20,1,1);

5.update语句

-- update 更新语句
update  tb_user set name = 'lisi' where id = 4;

6.delete语句

-- delete 删除语句
delete from tb_user where id = 5;

7.函数

-- 个数
select count(*) as totalCount from tb_user;
-- 总和
select sum(age) as totalAge from tb_user;
-- 平均值
select avg(age) as avgAge from tb_user;
-- 最大
select max(age) as maxAge from tb_user;
-- 最小
select min(age) as minAge from tb_user;

8.事务

create table runoob_transaction_test ( id int(5)) engine = innodb; # 创建数据库

select * from runoob_transaction_test;

begin;
insert into runoob_transaction_test (id) values (5);

insert into runoob_transaction_test (id) values (6);

commit;

select * from runoob_transaction_test;

begin;
insert into runoob_transaction_test (id) values (7);
rollback;
select * from runoob_transaction_test;
commit;

SQL 连接(JOIN)

    INNER JOIN:如果表中有至少一个匹配,则返回行
    LEFT JOIN:即使右表中没有匹配,也从左表返回所有的行
    RIGHT JOIN:即使左表中没有匹配,也从右表返回所有的行
    FULL JOIN:只要其中一个表中存在匹配,则返回行

0.Sql 之 笛卡尔积

注释:INNER JOIN 与 JOIN 是相同的。

数据库表:

首先,我们需要先明白一个概念——笛卡尔积:

笛卡尔积是指在数学中,两个集合X和Y的笛卡尓积(Cartesian product),又称直积,表示为X × Y,第一个对象是X的成员而第二个对象是Y的所有可能有序对的其中一个成员。
例子:
假设集合A={a, b},集合B={0, 1, 2},则两个集合的笛卡尔积为
{
(a, 0),
(a, 1), 
(a, 2), 
(b, 0), 
(b, 1), 
(b, 2)
}。

现在来观察上面两个表形成的笛卡尔积:

1.Sql 之 inner join

注释:INNER JOIN 与 JOIN 是相同的。(相当于取交集)

注释:INNER JOIN 关键字在表中存在至少一个匹配时返回行。

SQL join 用于把来自两个或多个表的行结合起来。

最简单的就是内连接,inner join.

-- 使用where连接
SELECT
	p.id,
	p.NAME,
	pd.id AS _id,
	pd.pid,
	pd.price,
	pd.num 
FROM
	product p,
	product_detail pd 
WHERE
	p.id = pd.pid;	

-- 	inner join or join
	
	SELECT
	p.id,
	p.NAME,
	pd.id AS _id,
	pd.pid,
	pd.price,
	pd.num 
	from product p
	INNER join product_detail pd
	on p.id = pd.pid;

以上两种方式查询的结果是一样的。(两个都相当于内连接)

总结:内连接inner join是将两个或两个以上的表连接起来,用on来连接,只用当on所限制的条件满足的时候,笛卡尔积组成的结果行才会返回。

如下图:(只有on后面的条件,p.id = pd.pid成立的时候)

2.Sql 之 left join | left outer join

注释:LEFT JOIN 关键字从左表(Websites)返回所有的行,即使右表(access_log)中没有匹配。

-- left join or left outer join
	
SELECT
	p.id,
	p.NAME,
	pd.id AS _id,
	pd.pid,
	pd.price,
	pd.num 
	from product p
	left join product_detail pd
	on p.id = pd.pid;
	

在左连接的基础上加上过滤条件

SELECT
	p.id,
	p.NAME,
	pd.id AS _id,
	pd.pid,
	pd.price,
	pd.num 
	from product p
	left join product_detail pd
	on p.id = pd.pid and p.id = 1

使用where进行过滤的

注意:在使用 left jion 时,onwhere 条件的区别如下:

  • 1、 on 条件是在生成临时表时使用的条件,它不管 on 中的条件是否为真,都会返回左边表中的记录。
  • 2、where 条件是在临时表生成好后,再对临时表进行过滤的条件。这时已经没有 left join 的含义(必须返回左边表的记录)了,条件不为真的就全部过滤掉。

3.Sql 之 right join | right outer join

注释:RIGHT JOIN 关键字从右表(table2)返回所有的行,即使左表(table1)中没有匹配。如果左表中没有匹配,则结果为 NULL。

select 
p.id,
p.name,
pd.id as _id,
pd.pid,
pd.price,
pd.num
from product p
right join product_detail pd
on p.id = pd.pid

加入过滤条件的有连接 on 后面接and进行过滤

select 
p.id,
p.name,
pd.id as _id,
pd.pid,
pd.price,
pd.num
from product p
right join product_detail pd
on p.id = pd.pid
and pd.pid = 1

select 
p.id,
p.name,
pd.id as _id,
pd.pid,
pd.price,
pd.num
from product p
right join product_detail pd
on p.id = pd.pid
-- and pd.pid = 1
where pd.pid = 1

使用on过滤和where过滤跟上面的左连接是一样的。

4.Sql 之 full join | full outer join

注释:FULL OUTER JOIN 关键字返回左表(Websites)和右表(access_log)中所有的行

(使用方式如上面两种那样,但是mysql不支持全连接)

5.Sql 之 union and union all

但是可以使用union关键字来实现所谓的全连接


SELECT
	p.id,
	p.NAME,
	pd.id AS _id,
	pd.pid,
	pd.price,
	pd.num 
FROM
	product as p
	left JOIN product_detail pd
	ON p.id = pd.pid
	
UNION
 
 SELECT 
 p.id,
	p.NAME,
	pd.id AS _id,
	pd.pid,
	pd.price,
	pd.num 
FROM
 product p
 right join product_detail pd
 on p.id = pd.pid;

上面是使用的是union,不显示重复行,但是如果把union换成union all 那么就会把重复行显示出来,

效果如下图:(union all)

6.Sql 之 natural join

SELECT
	* 
FROM
	product
	NATURAL JOIN product_detail

注释:自然连接默认是匹配两个表列名相同的,然后不重复显示。

如下图,将数据库表设计改变:(改变第一个表的id名为pid)

结果如下:

哪些情况需要建立索引

  • 1.主键自动建立唯一索引
  • 2.频繁作为查询条件的字段应该建立索引
  • 3.查询中与其他表关联的字段,外键关系建立索引
  • 4.频繁更新的字段不适合创建索引 --- 因为每次更新不单单是更新了记录还会更新索引,加重了IO负担
  • 5.where条件里用不到的字段不创建所以
  • 6.单键/组合索引的选择问题,who?(在高并发下倾向创建组合索引)
  • 7.查询中排序的字段,排序字段若通过索引去访问将大大提高排序的速度
  • 8.查询中统计或者分组字段

哪些情况不要创建索引

1.表记录太少

2.经常增删改的表 (why:提高了查询速度,同时却会降低更新表的速度,如对表进行insert,update,delete,因为在更新表时,mysql不仅要保存数据,还需要保存一下索引文件)。

3.数据重复且分布平均的表字段,因此应该只为最经常查询和最经常排序的数据列建立索引。

​ 注意:如果某个数据列包含许多重复数据的内容,为它建立索引就没有太大的实际效果。

性能分析> Explain

解释:

使用Explain关键字可以模拟优化器执行sql查询语句,从而知道mysql是如何处理你的sql语句。
分析你的查询语句或者是表结构的性能瓶颈。

能干嘛:

  • 1.表的读取顺序
  • 2.数据读取操作的操作类型
  • 3.哪些索引可以使用
  • 4.哪些索引被实际引用
  • 5.表之间的引用
  • 6.每张表有多少行被优化器查询

语法:

explain sql

id:

select 查询的序列,包含一组数字,表示查询中执行select字句或操作表的顺序
三种情况:
	1.id相同,执行顺序由上到下
	2.id不同,如果是子查询,id序号会递增,id值越大优先级越高,越先被执行。
	3.id不同,同时存在

select_type:

查询的类型,主要是用于区别 普通查询、联合查询、子查询等的复杂查询
	1.simple
		简单的select查询,查询中不包含子查询或者union
	2.primary
		查询中若包含任何复杂的子部分,最外层查询则被标记为primary。
	3.subquery
		在select或where列表中包含子查询
	4.derived
		在from列表中包含的子查询被标记为derived(衍生) mysql会递归执行这些子查询,把结果放在临时表中
	5.union
		若第二个select出现在union之后,则会标记为union;若union包含在from子句的子查询中,
外层select将标记为:derived
	6.union result
		从union表获取结果的select、。

table:

显示这一行的数据是关于哪一张表的

type:

显示查询使用了哪种类型:(好>查)
system > const > eq_ref > ref > range > index > all

system:
	表只用一行记录(等于系统表),这是const类型的特列,平时不会出现,这个也忽略不计

const:
	表示通过索引一次就找到了,const用于比较primary key或unique索引。因为只匹配一行数据,索引很快,
如果将主键置于where列表中,mysql就能将该查询转换为一个常量。

eq_ref:
	唯一性索引扫描,对于每个索引键,表中只有一条记录与之匹配。常见于主键或唯一索引扫描

ref:
	非唯一性索引扫描,返回匹配某个单独值的所有行,本质上也是一种索引访问,它返回所有匹配某个单独值的行
然而,它可能会找到多个符合条件的行,所以它应该属于查找和扫描的混合体。

range:
	只检索给定的范围的行,使用一个索引来选择行。key列显示使用了哪个索引,一般就是在你的where字句中出
现了between,<,> ,in 等查询,这种范围扫描索引比全表扫描要好,因为它只需要开始于索引的某一点,
而结束与另一点,不用扫描全部索引。
    
index:
    full index scan, index 与 all区别为index类型只遍历索引树,这通常比all快,因为索引文件通常比
数据文件小。(也就是说虽然all和index都是读全表,但是index是从索引中读取的,而all是从硬盘中读取的)
    
all:
    full table scan,将遍历全表以找到匹配的行。

备注:一般来说:得保证查询至少达到range级别,最好能达到ref。

possible_keys:

显示可能应用在这张表中的索引,一个或多个。
查询涉及到的字段上若存在索引,则该索引将被列出,但不一定被查询实际使用。

key:

实际使用的索引。如果为null,则没有使用索引。
查询中若使用了覆盖索引,则该索引和查询的select字段重叠。

key_len:

表示索引中使用的字节数,key 通过该列计算查询中使用的索引的长度,在不损失精确性的情况下,长度越短越好。
key_len显示的值为索引字段的最大可能长度,并非实际使用长度,即key_len是根据表定义计算得到,而不是通过
表内检索得出。

ref:

显示索引的哪一列被使用了,如果可能的话,是一个常数,哪些列或常量被用于查找索引列上的值

rows:

根据表统计信息及索引选用情况,大致估算出找到所需的记录所需要读取的行数

extra:

包含不适合在其他列中显示但十分重要的额外信息

1.using filesort
	说明mysql会对数据使用一个外部的索引排序,而不是按照表内的索引顺序进行读取。mysql中无法利用索引
完成的排序操作称为“文件排序”。

2.using temporary
	使用了临时表保存中间结果,mysql在对查询结果排序时使用临时表,常见于排序order by 和
分组查询group by

3.using index 
	表示相应的select操作中使用了覆盖索引,避免访问了表的数据行,效率不错。
如果同时出现了using where,表明索引被用来执行索引键值的查找。如果没有同时出现using where,
表明索引用来读取数据而非执行查找动作。

4.using where
	表明使用了where过滤

5.using join buffer 
	使用了连接缓存

6.impossible where
	where字句的值总是false,不能用来获取让任何元组

7.select tables optimized away 
	在没有group by字句的情况下,基于索引优化min/max操作或者对于myisam存储引擎优化count(*)操作。
不必等到执行阶段在进行计算,查询执行计划生成的阶段即完成优化

8.distinct
	优化distinct操作,在找到第一匹配的元组后即停止找同样值的动作。 

索引失效

1.全值匹配我最爱

2.最佳左前缀法则(如果索引了多列,要遵守最左前缀法则,指的是查询从索引的最左列并且不跳过索引中的列)

3.不在索引列上做任何操作(计算,函数,(自动或手动)类型转换),会导致索引失效而转向全表扫描

4.存储引擎不能使用索引中范围条件右边的列

5.尽量使用覆盖索引(只访问索引的查询(索引列和查询列一致)),减少select *

6.mysql在使用不等于(!=货值<>)的时候无法使用索引而导致全表扫描、

  1. is null. is not null 也无法使用索引

8.like 以通配符开头('%abc...')mysql索引失效会变成全表扫描的操作

9.字符串不加单引号索引失效

10.少用or,用它来连接时会索引失效

程序yuan
原文地址:https://www.cnblogs.com/ooyhao/p/11258246.html