走向面试之数据库基础:二、SQL进阶之case、子查询、分页、join与视图
一、CASE的两种用法
1.1 等值判断->相当于switch case
(1)具体用法模板:
CASE expression
WHEN value1 THEN returnvalue1
WHEN value2 THEN returnvalue2
WHEN value3 THEN returnvalue3
ELSE defaultreturnvalue
END
(2)具体使用示例:
假设我们有一个论坛网站,其中有一张User表{ UId,Name,Level },Level是一个int类型,代表了用户等级类型,例如:1代表骨灰,2代表大虾等;我们就可以用CASE来对其进行等值判断了:
select Name,Rank=(
case Level
when 1 then '骨灰'
when 2 then '大虾'
when 3 then '菜鸟'
end
)
from User
1.2 条件判断->相当于if else if else
(1)具体用法模板:
CASE
WHEN condition1 THEN returnvalue1
WHEN condition2 THEN returnvalue2
WHEN condition3 THEN returnvalue3
ELSE defaultreturnvalue
END
注意:then后面返回的数据类型要一致, returnvalue1、 returnvalue2、 returnvalue3的数据类型必须一致。
(2)具体使用示例:
假设我们有一张Score成绩表,里面记录有所有同学的成绩,此时我们想要对所有成绩进行一个评级,比如成绩如果>=90那么则评为A级,>=80且<90则评为B级,这里我们怎来写呢?
select studentId,rank=(
case
when english between 90 and 100 then 'A'
when english between 80 and 89 then 'B'
when english between 70 and 79 then 'C'
when english between 60 and 69 then 'D'
when english < 60 then 'E'
else '缺考'
end
)
from Score
二、子查询的用法
2.1 子查询初步
就像使用普通的表一样,被当作结果集的查询语句被称为子查询。所有可以使用表的地方几乎都可以使用子查询来代替。例如:我们如果要找到所有计科一班的同学信息,可以首先通过T_Class表找到计科一班的Id,然后再在T_Student表中找到所有ClassId为计科一班Id的行即可。
select * from T_Student where ClassId=
(
select Id from T_Class where Name='计科一班'
)
2.2 单值子查询
只有返回且仅返回一行、一列数据的子查询才能当成单值子查询。例如我们上面提到的例子,子查询中只返回了一个ClassId,这就是单值子查询。当子查询跟随在=、!=、<、<=、>、>=,<> 之后,或子查询用作表达式,只能使用单值子查询。
2.3 多值子查询
如果子查询是多行单列的子查询,这样的子查询的结果集其实是一个集合,那么可以使用in关键字代替=号。例如:我们如果想快速地在T_Student表中删除计科一班和计科二班的所有学生记录,我们可以使用in关键字:
delete from T_Student where ClassId in
(
select Id from T_Class where Name='计科一班' or Name='计科二班'
)
2.4 Exists—你存在我深深的脑海里
exists是用来判断是否存在的,当exists查询中的查询存在结果时则返回真,否则返回假。not exists则相反。
exists做为where 条件时,是先对where 前的主查询询进行查询,然后用主查询的结果一个一个的代入exists的查询进行判断,如果为真则输出当前这一条主查询的结果,否则不输出。
exists后面的查询称为相关子查询,即子查询的查询条件依赖于外层父查询中的某个属性值,其处理过程一般为:先取外层查询中的第一个元组,根据它与内层查询中的相关属性值处理内层查询,若where子句返回true,则将此元组放入结果表中,然后取外层查询中的下一个元组,重复这个过程直到全部检查完毕为止。
例如:我们有一张人员信息表,里边有一个人员类型Id字段(pTypeId),它是一个外键,对应着人员类型表的主键ptId。如果我们有以下的SQL语句,使用Exists关键字则可以有如下的理解:
select * from Employee e where exists
(select * from EmployeeType et where e.pTypeId=et.ptId)
那么,在这句SQL的执行过程中,我们可以将其理解为一个双重的for循环,外边是主表的循环遍历,然后将其放到一个temp变量中,再进入从表的for循环,并与从表的项进行一个一个的按照匹配规则(这里是e.pTypeId=et.ptId)进行匹配,如果有匹配成功则返回true,并且将这一行记录放到要返回的结果集中,否则返回false。
三、手写分页SQL代码
这里假设每页的页大小为10条记录
3.1 利用Top N进行简单分页
(1)如果我们要获取第一页的数据,也就是前10个:
select top 10 * from Account
(2)现在我们要获取第一页之后的数据,也就是第20个~最后一个:
select * from Account where Id not in (select top 10 Id from Account)
(3)现在我们对第20个~最后一个的数据集中取前10个也就成为第二页的数据了:
select top 10 * from Account where Id not in (select top 10 Id from Account)
(4)将上述代码总结为分页代码,设页大小为pageSize,请求页号为pageIndex:
select top @pageSize * from Account where Id not in (select top ((@pageIndex-1)*@pageSize) Id from Account)
PS:这种分页方式的缺点是如果要取很多页之后的数据,那么就要取出前面很多页的ID,查询开销较大,执行效率也就低下。
从图中可以看出,在小数据量的对比下,Top N的查询开销较小。但是在大数据量的对比下,Row_Number的方式会取得更高的查询效率以及较小的开销。
3.2 利用Row_Number()进行高效分页
(1)SQL Server 2005后增加了Row_Number函数,可以简化分页代码的实现。首先,Row_Number()是一个排序函数,它可以生成一个有序的行号(如果单靠ID来排序,中间存在断层,例如某一个ID行已经被删除了)。根据MSDN的定义:返回结果集分区内行的序列号,每个分区的第一行从 1 开始。而排序的标准是什么呢?这个就要靠紧跟其后的OVER()语句来定义了。这里我们可以通过一个示例来看看,其生成的行号如何。
select *,ROW_NUMBER() OVER(order by Id) as RowNum from Account
(2)根据ROW_NUMBER()的使用,我们可以将其应用到分页上,于是我们可以写出以下的代码来实现获取第二页的数据集:
select * from (
select *,ROW_NUMBER() OVER(Order by Id) as rownum from Account
) as t
where t.rownum between 11 and 20
order by t.Id asc
(3)将上述代码总结为分页代码,设页大小为pageSize,请求页号为pageIndex:
select * from (
select *,ROW_NUMBER() OVER(Order by Id) as rownum from Account
) as t
where t.rownum between (@pageIndex-1)*pageSize+1 and @pageSize*pageIndex
order by t.Id asc
四、各种连接—JOIN
4.1 Join==Inner Join
默认情况下,使用Join则代表Inner Join内连接,表示两个表根据某种等值规则进行连接。例如下面示例:查询所有学生的学号、姓名及所在班级
select p.Id,p.Name,c.Name from T_Person p join T_Class c on p.ClassId=c.Id
4.2 Left Join
例如:查询所有学生(参加及未参加考试的都算)及成绩,这里涉及到学生表及成绩表,题目要求参加及未参加考试的都要列出来,于是以学生表为基准,对成绩表进行左连接:
select * from Student s
left join SC sc on s.S#=sc.S#
可以通过运行结果图,看到王二小这个童鞋没有参加考试,也就没有成绩。
4.3 Right Join
例如:要查询出所有没有参加考试(在成绩表中不存在的学生)的学生的姓名。于是还是可以以学生表为基准,但是要对成绩表进行右连接:
select * from Student s
right join SC sc on s.S#=sc.S#
4.4 Cross Join
此种连接在实际应用中不算常见的,但却是理论基础,因为它代表了笛卡尔积。其实,所有连接方式都会先生成临时笛卡尔积表,笛卡尔积是关系代数里的一个概念,表示第一个表的行数乘以第二个表的行数等于笛卡尔积结果集的大小。
select * from Student s
cross join SC sc
这里假如Student表中有10行记录,SC表中有20行记录,那么两表进行交叉连接笛卡尔积运算会得到10*20=200行记录的结果集。
五、视图
5.1 三个角度看视图
从用户角度来看,一个视图是从一个特定的角度来查看数据库中的数据。
从数据库系统内部来看,一个视图是由SELECT语句组成的查询定义的虚拟表。
从数据库系统内部来看,视图是由一张或多张表中的数据组成的;从数据库系统外部来看,视图就如同一张表一样,对表能够进行的一般操作都可以应用于视图,例如查询,插入,修改,删除操作等。
5.2 创建视图
例如,我们可以创建一个学生成绩详细信息视图,对一个需要进行三表连接的查询进行封装:
create view vw_sc
as
select s.S#,s.Sname,c.Cname,sc.Score from Student s
join SC sc on s.S#=sc.S#
join Course c on sc.C#=c.C#
然后,我们对vw_sc进行select查询:
5.3 视图的注意事项
(1)视图在操作上和数据表没有什么区别,但两者的差异是其本质是不同:数据表是实际存储记录的地方,然而视图并不保存任何记录。
(2)相同的数据表,根据不同用户的不同需求,可以创建不同的视图(不同的查询语句)。
走向面试之数据库基础:二、SQL进阶之case、子查询、分页、join与视图的更多相关文章
- 走向面试之数据库基础:一、你必知必会的SQL语句练习-Part 1
本文是在Cat Qi的参考原帖的基础之上经本人一题一题练习后编辑而成,非原创,仅润色而已.另外,本文所列题目的解法并非只有一种,本文只是给出比较普通的一种而已,也希望各位园友能够自由发挥. 一.三点一 ...
- 走向面试之数据库基础:三、SQL进阶之变量、事务、存储过程与触发器
一.变量那点事儿 1.1 局部变量 (1)声明局部变量 DECLARE @变量名 数据类型 ) DECLARE @id int (2)为变量赋值 SET @变量名 =值 --set用于普通的赋值 SE ...
- 数据库子查询和join的比较
子查询进行SELECT语句嵌套查询,可以一次完成很多逻辑上需要多个步骤才能完成的SQL操作.子查询虽然很灵活,但是执行效率并不高. select goods_id,goods_name from go ...
- 在论坛中出现的比较难的sql问题:40(子查询 销售和历史库存)
原文:在论坛中出现的比较难的sql问题:40(子查询 销售和历史库存) 最近,在论坛中,遇到了不少比较难的sql问题,虽然自己都能解决,但发现过几天后,就记不起来了,也忘记解决的方法了. 所以,觉得有 ...
- 在论坛中出现的比较难的sql问题:7(子查询 判断某个字段的值是否连续)
原文:在论坛中出现的比较难的sql问题:7(子查询 判断某个字段的值是否连续) 最近,在论坛中,遇到了不少比较难的sql问题,虽然自己都能解决,但发现过几天后,就记不起来了,也忘记解决的方法了. 所以 ...
- 【SQL重温】面试之数据库基础练习
简介 最近在练习SQL基础,首先感叹一下,在机器上写和在纸上写还是有区别的. 本文的练习题目请点击此链接进行查看:http://www.cnblogs.com/edisonchou/p/3878135 ...
- PHP面试 MySQL数据库基础
MySQL数据库基础 MySQL数据类型 整数类型:TINYINT SMALLINT MEDIUMINT INT BIGINT 属性:UNSIGNED 长度:可以为整数类型指定宽度,列 ...
- 【SQL必知必会笔记(1)】数据库基础、SQL、MySQL8.0.16下数据库、表的创建及数据插入
文章目录 1.数据库基础 1.1 数据库(database) 1.2 表(table) 1.3 列和数据类型 1.4 行 1.5 主键 2.什么是SQL 3.创建后续练习所需数据库.表(MySQL8. ...
- MS sql server 基础知识回顾(二)-表连接和子查询
五.表连接 当数据表中存在许多重复的冗余信息时,就要考虑将这些信息建在另一张新表中,在新表中为原表设置好外键,在进行数据查询的时候,就要使用到连接了,表连接就好像两根线,线的两端分别连接两张表的不同字 ...
随机推荐
- "Fatal error: Call to undefined function: file_put_contents()"
打开页面时提示这个错误: Fatal error: Call to undefined function: file_put_contents() 意思是请求未定义的函数,出现这个提示通常有两种情况: ...
- windows下指定格式文件转移
#放在目录下执行 1.bat 作用:将该目录下所有mp4格式的文件转移至该目录下的target目录下 须保证target目录不存在@echo off md target\ for /f "d ...
- Eclipse启动时发生An internal error occurred during: "Initializing Java Tooling".错误的解决方法
问题描述: Eclipse启动时发生An internal error occurred during: "Initializing JavaTooling".错误的解决方法 解决 ...
- AugularJS特性
AugularJS特性 AngularJS是一个新出现的强大客户端技术,提供给大家的一种开发强大应用的方式.这种方式利用并且扩展HTML,CSS和javascript,并且弥补了它们的一些非常明显的不 ...
- 《UML大战需求分析》阅读随笔(一)
UML:Unified Modeling Language(统一建模语言) 作为我专业学科里的一门语言,其目的就是交流,同客户交流,同自己交流. 用图像和文字,详细地讲解将要做的工程的 需求和功能细节 ...
- iOS之防止用户重复点击Button(按钮)问题
在项目中,我们往往会遇到这样的问题:因为网络较慢的原因,用户会不耐烦的一直去点击按钮,这样导致的结果时:相关代码一遍一遍的被重复执行,如果按钮的事件是网络请求的话,这样又导致一种网络请求的循环.所以我 ...
- oracle(sql)基础篇系列(三)——数据维护语句、数据定义语句、伪列
DML语句 insert 向表中插入新的记录 --三种插入方式 --(1)不写字段的名字,直接按照字段的顺序把值逐个往里插 insert into dept2 values(50,'DANAM ...
- Hibernate注解方式配置-继承关系
在JPA中,实体继承关系的映射策略共有三种:单表继承策略(table per class).Joined策略(table per subclass)和Table_PER_Class策略. 1.单表继承 ...
- hihocoder挑战赛13A
#1191 : 小W与网格 描述 给定一个n*m的网格,左上角(1, 1),右下角(n, m). 小w在(i, j),他会从"上左下右"四个方向中选定两个不同但正交的方向,然后他只 ...
- 2016 Multi-University Training Contest 1 G. Rigid Frameworks
Rigid Frameworks Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others) ...