本章节我们讨论的SQL写法,我目前还没有想到高效的场景,所以称之为诡异篇,算是几种要绕开的写法吧。
1用左联接代替分组聚合运算
1.1 数据环境
drop table test1;
create table test1 as select * from dba_objects where rownum<1000;
alter table test1 add constraint pk_test1 primary key (object_id);
commit;
1.2 业务要求
检索每个Owner里面最大的object_id
1.3 SQL写法
常规写法
select t1.owner, max(t1.object_id) as max_id
from test1 t1
group by t1.owner
order by 1,2;
左联接诡异写法
select t1.owner, t1.object_id as max_id
from test1 t1
left join test1 t2
on t1.owner=t2.owner
and t1.object_id<t2.object_id
where t2.object_id is null
order by 1,2;
我们可以用这个案例理解一下不等连接,至于实际写SQL时,我觉得不要用左联接写法,因为性能较低。
2用内连接写关系除法
2.1 数据环境
create table student(stu_name varchar2(20),subject_id varchar2(10));
create table subject(subject_id varchar2(10),subject_name varchar2(20),teacher varchar2(20));
insert into student values('狗蛋','M');
insert into student values('狗蛋','C');
insert into student values('狗蛋','P');
insert into student values('翠花','M');
insert into student values('翠花','C');
insert into student values('小红','M');
insert into subject values('M','数学','张老师');
insert into subject values('C','语文','张老师');
insert into subject values('M','数学','李老师');
insert into subject values('C','语文','李老师');
insert into subject values('P','物理','李老师');
insert into subject values('M','数学','孙老师');
insert into subject values('P','物理','孙老师');
commit;
2.2 业务要求
求同时选了数学和语文的学生姓名,即狗蛋和翠花
2.3 SQL写法
with tmpChinese as
(select sd.stu_name
from student sd
, subject sj
where sd.subject_id=sj.subject_id
and sj.subject_id='C'),
tmpMath as
(select sd.stu_name
from student sd
, subject sj
where sd.subject_id=sj.subject_id
and sj.subject_id='M')
select distinct tc.stu_name
from tmpChinese tc
, tmpMath tm
where tc.stu_name=tm.stu_name;
至于什么是关系除法,以及常规写法,参见本人另一篇博客,链接如下:
https://blog.csdn.net/songjian1104/article/details/100594315
用内连接写关系除法,虽然好理解,也能避开Filter查询,但是如果除数条目太多,用这种写法是不合适的,因为表连接次数太多,性能太低,SQL也会变得超级长(比如这里的语文数学两门科目编程100个科目,就要构造100个with查询或者子查询)。