【原创】复杂sql语句

参考:

https://www.cnblogs.com/zhangkaimin/p/11386732.html

理解:

1,复杂sql语句,一般是用 子查询嵌套 和 join 连接导致的,结合in, not in, any, all, exists,  not exists;

2,子查询是分为关联子查询非关联子查询,子查询的where是否与外部查询的表字段有关联;

3,子查询的返回有4种情况(单一值,一行,一列,多行多列的子表)对应不同的查询条件

(1)单一值可以用在where子句中的 =、 >、>=、<、<=、!=查询条件,select 子句中作为一个字段返回,order by子句中作为排序条件

(2)一行的时候,可以当做批量单一值来用,只能使用 = 条件。

SELECT * FROM t1 WHERE (1,2) = (SELECT column1, column2 FROM t2);//不支持!=,<,<=,>,>=
SELECT * FROM t1 WHERE ROW(1,2) = (SELECT column1, column2 FROM t2);

(3)一列用在where子句中的 in,any,all等查询条件

SELECT * FROM t1 WHERE id in (SELECT id FROM t2);
select
* from student where 班级='01' and age > all (select age from student where 班级='02'); #相当于 select * from student where 班级='01' and age > (select max(age) from student where 班级='02');
select
* from student where 班级='01' and age > any (select age from student where 班级='02'); #相当于 select * from student where 班级='01' and age > (select min(age) from student where 班级='02');

(4)子表可以用在where子句中的 exists,not exists的查询条件;或者from子句后面(此时子表必须命名,并且不能为有关联的子查询)

#查找总访问量(count 字段)大于 200 的网站是否存在
SELECT Websites.name, Websites.url 
FROM Websites 
WHERE EXISTS (SELECT count FROM access_log WHERE Websites.id = access_log.site_id AND count > 200);

4,join的使用:

(1)mysql中没有full outer join;只有left outer join或者right outer join

(2)mysql中left join和left outer join效果一样,right也是;left 或 right的作用是连接字段可以在另一个表中不存在

(3)mysql有一个cross join ,相当于inner join 不加on,或者 from两个表的效果:from A, B

(4)join都是笛卡尔积,关键是要理解连接字段在表中的存在情况

(5)join和group by一起使用作用更大

//1
select * from A inner join B on A.key_a = B.key_b;//AB交集的笛卡尔积,可能比A或B的行数还多
//2
select * from A left join B on A.key_a = B.key_b;//A全部的笛卡尔积
//3
select * from A right join B on A.key_a = B.key_b;//B全部的笛卡尔积
//4
select * from A left join B on A.key_a = B.key_b where B.key_b is null;//在A中不在B中的行数,笛卡尔积//此时left join可以替换为left outer
//5
select * from A right join B on A.key_a = B.key_b where A.key_a is null;//在B中不在A中的行数,笛卡尔积
//6:结合4和5
select * from A left join B on A.key_a = B.key_b where B.key_b is null;
union
select * from A right join B on A.key_a = B.key_b where A.key_a is null;//要么在A中要么在B中,这个说法也不具体,具体是连接的字段的值要么在A中存在,要么在B中存在
//7:
select * from A inner join B;//不加on条件, 就是A表行数和B表行数的笛卡尔乘积多个结果

5,union和union all的使用

(1)用于合并两个或多个 SELECT 语句的结果集
(2)每个 SELECT 语句必须拥有相同数量的列
(3)列也必须拥有相似的数据类型
(4)每个 SELECT 语句中的列的顺序必须相同
(5)union会去重,union all不会去重,去重的规则是一行中所有列都对应相同才去重

6,复杂sql语句可能有多种实现写法;

SQL执行顺序

FROM:首先确定要查询的表。
ON:根据FROM子句中的表进行连接,并应用连接条件。
JOIN:执行表之间的连接操作,生成笛卡尔积,形成临时中间表。
WHERE:应用筛选条件,从临时中间表中过滤掉不需要的记录。
GROUP BY:按照指定的字段对筛选后的记录进行分组,形成临时中间表。
HAVING:对分组后的记录应用聚合函数或普通筛选条件,生成新的临时中间表。
SELECT:选择要查询的字段,可以是普通字段查询或聚合函数查询,生成新的临时中间表。
DISTINCT:对查询结果去重,生成新的临时中间表。
ORDER BY:根据指定的字段对查询结果进行排序,生成新的临时中间表。
LIMIT:对排序后的结果进行分页,生成最终返回给客户端的数据。 limit 0,10;或者limit 10 offset 0

写法注意项:

order by-limit-offset的结构顺序必须是

select * from req_log where id >100 ORDER BY id asc limit 0,10;
select * from req_log where id >100 ORDER BY id asc limit 10 OFFSET 0;#同上

查询语句同时出现了where,group by,having,order by

执行顺序和编写顺序是:

1.执行where xx对全表数据做筛选,返回第1个结果集。

2.针对第1个结果集使用group by分组,返回第2个结果集。

3.针对第2个结果集中的每1组数据执行select xx,有几组就执行几次,返回第3个结果集。

4.针对第3个结集执行having xx进行筛选,返回第4个结果集。

5.针对第4个结果集排序。

举例:

按由高到低的顺序显示个人平均分在70分以上的学生姓名和平均分,为了尽可能地提高平均分,在计算平均分前不包括分数在60分以下的成绩,并且也不计算某人(jr)的成绩。
分析:
1.要求显示学生姓名和平均分
因此确定第1步
select s_name,avg(s_score) from student
2.计算平均分前不包括分数在60分以下的成绩,并且也不计算贱人(jr)的成绩
因此确定第2步 
where score>=60 and s_name !=’jr’
3.显示个人平均分
相同名字的学生(同一个学生)考了多门科目 因此按姓名分组
确定第3步 
group by s_name
4.显示个人平均分在70分以上
因此确定第4步 
having avg(s_score)>=70
 5.按由高到低的顺序
因此确定第5步
order by avg(s_score) desc

结果

select s_name, avg(s_score) as avg_s_score from students 
where s_score>=60 and s_name !='jt'
group by s_name
having avg_s_score>=70
order by avg_s_score desc;

实战举例

参考:https://www.cnblogs.com/tkzc2013/p/9962363.html

 

posted @ 2020-10-27 12:41  小匡程序员  阅读(1462)  评论(0编辑  收藏  举报