..when comexp then returnvalue
Else
Returnvalue
End
Case表达式第二种:
case when Boolean then returnvalue
..when Boolean then return value
Else
Returnvalue
End
Decode函数:
decode(exp,
value1,res1,
value2,res2,….,
valuen resn,
elseva lue)。
3.4 使用案例
Case 第一种用法:
Case 第二种用法:
Decode用法:
上文提到过null,碰到null的时候要注意,比如:
这种情况可以这样处理:
如果用decode函数:
3.5 使用场景
当我们的sql要求根据不同的条件返回不同的值时,可以使用。
4 exists与in、not exists与not in
4.1 学习目标
掌握exists与in的、not exists与not in的用法,了解其内部的执行顺序 与执行原理,知道什么情况下用exists,什么情况下用in。
4.2 要点
1. Exists 用于只能用于子查询,可以替代in,若匹配到结果,则退出内部
查询,并将条件标志为true,传回全部结果资料。
2. 若子查询结果集比较小,优先使用in,若外层查询比子查询小,优先使用exists。因为若用in,则oracle 会优先查询子查询,然后匹配外层查询,若使用exists,则oracle 会优先查询外层表,然后再与内层表匹配。最优化匹配原则,拿最小记录匹配大记录。
4.3 语法
In:Select select_fields from table_name where field_name in(select clause);
Exists:Select select_fields from table_name exists (select clause)
4.4 使用案例
查询员工部门编号在部门表中存在的员工记录:
以上语句可以用Exist替换:
另外not in和not exists在某些情况下也可以相互转换,但是要注意一点,not in中的子查询返回的结果集包含null值的时候,查询会失效。例如我想查询对应员工记录数为0的部门。如下:
用not exists:
以上语句不能用not in替换:
查询失效无记录返回。注意这并不是oracle的bug,因为在oracle中null不表示空,而是表示未知,当使用not in的时候,如果子查询返回的结果集中包含null值,我们并不知道外层查询的记录在不在子查询返回的结果集之内,所以无记录返回。虽然这样,但是并不表示not in和not exists是完全不可以转换的,比如子查询所选的字段在对应的表中没有null值,这时not in和not exists是可以相互转换的。或者在某些情况下内层子查询加上field_name is not null限制条件也是可以的。
4.5 使用场景
当内层查询返回的结果集较小时,用in 或者not in效率较高。当内层子查询返回的结果集比较大时,用exists或者not exists执行的效率较高。
5 行列互换
5.1 学习目标
掌握列转行技术和常用的行专列技术。
5.2 要点
行专列的情况有多种,不同的情况侧重点也不一样。
5.3 语法
5.4 使用案例
1. 列转行
第一种方法:需要用到union或者union all:
第二种方法:用到model
2. 行专列,如我有escore表用来记录每个学生每个科目的成绩,如下:
如果我想将每个学生的成绩统计在一行上,如:
3 语文 11 数学 55 英语 66
则我可以使用如下sql:
这个sql表面上看没什么问题,但是仔细看一下三个结果集es、ys和ss,他们来源于同一个表,而且查询方法也类似,都是根据type的值去筛选的,这样就会对escore表查询三遍,严重影响查询速率,那这个sql我们如何去优化呢!
首先在你的脑海里面要有一种思路,根据需求,原先每个学生成绩有多行记录,现在要显示到一行上,那一般情况下我们是需要根据学生分组的。所以group by sid 这个是一定要有的,既然分组那我们可是使用oracle的聚合函数去求其他行的数据。至于科目字段目前都是已知的,也就是第2,4,6列显示的分别是英语、语文、数学这几个字,是常量,我们不用去考虑,那剩下的也就是最关键的,我们去求三科的成绩就可以了。
让我们再看一下escore表,当指针移到某一行数据时,当type=e时,我们就取到score,加到第三列上,那第五列和第七列就加0,也就是sum(decode(type,’e’,score,0)),其他列类似,这样group by时用到的聚合函数还有decode结合在一起使用,就可以完成我们的要求了,sql写出来时这样的:
3. 字符串组合的多行转一列,例如我有一张测试表如下:
我想根据id分组,将每一行的name连接起来,如下图是我想要的结果:
这种行转列不是真正意义的行转列,是多行数据的值拼接后显示到一列上,那这种情况怎么处理呢,首先分析一下:多行id相同的值转换成一行,一般情况下需要用到group by,但是对于字符串,oracle中没有一个聚合函数适合用到此处的字符串连接,那该怎么办呢?
在oracle中,有sys_connect_by_path(field_name,concat_value)函数,可以通过connect by来依次连接每一行的数据,connect by 的语法是这样的:
start with field1=1--以当前表达式返回true的行开始
connect by prior field2=field3--通过当前行查找下一行,也就是说某一行数据的field3字段等于当前行的field2,那就把这行数据作为下一行
有了这个思路,我们就可以用connect by 通过使用sys_connect_by_path(field_name,concat_value)这个函数,并且根据id分组,将字符串连接在一起,然后通过max聚合函数,选出每组最长的字符转就可以了,那剩下的也就是最关键的问题就是我怎样去使用connect by,通过当前行找到下一行呢?充分发散一下你的思维,看一下如下结果集:
那我下一步用如下思路使用connect by将所要的结果查询上来:
start with lg is null--以lg为null的行作为起始行
connect by prior rn=lg and prior id=id --当前行与其他行比较,满足这个条件的就作为下一行数据
总的查询结果如下:
其实怎么使用connect by 方法很多,例如如下sql也能完成:
5.5 使用场景
当开发过程中,需要我们将多列转换成多行或者将多行转换成多列的时候,就需要用到行列转换,要根据不同的情况确定不同的结果方案,典型的行列转换就这几种,还有一种比较复杂的是不定不定行专列,不定行转列需要用到oracle的package,在次先不做讲解。
6 merge into
6.1 学习目标
掌握merge into,学会使用merger into批量处理数据。
6.2 要点
1. MERGE语句是Oracle9i新增的语法,用来合并UPDATE和INSERT语句。
2. 过MERGE语句,根据一张表或子查询的连接条件对另外一张表进行查询,连接条件匹配上的进行UPDATE,无法匹配的执行INSERT。
3. 这个语法仅需要一次全表扫描就完成了全