掌握with子句用法,而且了解with子句可以提升查询效率的缘由。sql
嵌套with子句。oracle
With alias_name as (select1), --as和select中的括号都不能省略函数
alias_name2 as (select2),--后面的没有with,逗号分割,同一个主查询同级别地方,with子学习
查询只能定义一次测试
…优化
alias_namen as (select n) –与下面的实际查询之间没有逗号指针
Select ….code
如查询部门名称包含“A”的全部员工信息对象
--with clause排序
with a as
(select deptno from dept where dname like '%A%')
select * from emp where deptno in (select * from a);
with a as
(select deptno from dept where dname like '%A%'),--a结果集
a2 as(select * from a where deptno>20)--a1结果集直接从a中筛选
select * from emp where deptno in (select * from a2);
查询部门名称包含“A”而且部门编号大于20的全部员工信息
with a as
(select deptno from dept where dname like '%A%'),--a结果集
a2 as(select * from a where deptno>20)--a1结果集直接从a中筛选
select * from emp where deptno in (select * from a2);
查询部门名称包含“A”而且部门编号大于20的全部员工信息的另一种实现方式以下
with a as
(select deptno from dept where dname like '%A%')--a结果集
select * from emp where deptno in (--括号内层做为子查询,为第二级
with a2 as(select * from a where deptno>20)--a1结果集直接从a中筛选
select * from a2
);
那什么状况下能使用到with子句呢?如下我就举几个简单的例子,简单的说明如下:
我想测试成绩大于90的学生,我不想创建学生表,能够用到with子句
with stu as(
select '张娜' sname,99 score from dual union
select '王杰' ,35 from dual union
select '宋丽' ,85 from dual union
select '陈晓' ,73 from dual union
select '李元' ,100 from dual
)--with 组成一个临时的结果集,存放在用户的临时表空间
select * from stu where score>90
--查询销售部工资>1500或者销售部工资小于1000的员工
select * from emp where deptno=(select deptno from dept where dname ='SALES') and sal >1500
union all
select * from emp where deptno=(select deptno from dept where dname ='SALES') and sal <1000
--以上sql select deptno from dept where dname ='SALES'须要执行两次,影响效率
--可使用with优化一下
with salno as(select deptno from dept where dname ='SALES')
select * from emp where deptno=(select * from salno) and sal >1500
union all
select * from emp where deptno=(select * from salno) and sal <1000
掌握union,union all,minus,intersect的使用,可以描述集合运算,了解内部运行原理。
Union all 效率通常比union高。Union all内部不作排序工做,也不作剔除
重复行工做,而union则作这个工做。因此当数据量比较大的时候,能用union all的时候尽可能用union all。除了union all 默认不作排序和剔除重复行的操做外,
union,minus,intersect都默认按第1个查询结果的第1列进行升序排列,而且
不包含重复行。
(select resource 1)
Union/union all/minus/intersect
(select resource 2)
Union/union all/minus/intersect
(select resource 3)
……….
其中查询结果集的各个字段的类型可以互相兼容,而且总的结果集字段名与第一个结果集相同。
数据准备:
create table t1 as select rownum rn from dual connect by rownum<7;
create table t2 as select rownum+3 rn from dual connect by rownum<7;
insert into t1 values(1);
commit;
如今t1表中有两条相同的记录,其rn的值为1。
在进行集合运算时重复的记录被剔除:
当要对多个结果集进行集合操做时,但是使用集合操做。
会使用case表达式和decode函数,理解各个参数和返回值的含义。
Case表达式:
Decode函数的使用方法与case when类似,可是decode只能用等号匹配。
Case表达式第一种:
case exp when comexp then returnvalue
..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,
elsevalue)。
Case 第一种用法:
Case 第二种用法:
Decode用法:
上文提到过null,碰到null的时候要注意,好比:
这种状况能够这样处理:
若是用decode函数:
当咱们的sql要求根据不一样的条件返回不一样的值时,可使用。
掌握exists与in的、not exists与not in的用法,了解其内部的执行顺序 与执行原理,知道什么状况下用exists,什么状况下用in。
查询,并将条件标志为true,传回所有结果资料。
In:Select select_fields from table_name where field_name in(select clause);
Exists:Select select_fields from table_name exists (select clause)
查询员工部门编号在部门表中存在的员工记录:
以上语句能够用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限制条件也是能够的。
当内层查询返回的结果集较小时,用in 或者not in效率较高。当内层子查询返回的结果集比较大时,用exists或者not exists执行的效率较高。
掌握列转行技术和经常使用的行专列技术。
行专列的状况有多种,不一样的状况侧重点也不同。
第一种方法:须要用到union或者union all:
第二种方法:用到model
若是我想将每一个学生的成绩统计在一行上,如:
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写出来时这样的:
我想根据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也能完成: