三、复杂SQL语句

本文详细介绍了SQL语句的执行顺序,包括SELECT、FROM、WHERE、GROUP BY等子句的顺序。深入探讨了子查询、自连接、行列转换、分析函数、DECODE函数以及CASE WHEN的使用。此外,还讲解了如何使用EXISTS判断查询结果、删除重复记录的多种方法、分页查询和使用ROWNUM限制查询结果。内容涵盖了Oracle数据库中的高级SQL操作和性能优化技巧。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

  • 掌握 SQL语句的执行顺序、能分析复杂SQL语句的执行过程
  • 掌握 Oracle子查询、自连接、行列转换
  • 掌握分析函数、decode函数、 SELECT CASE WHEN的使用
  • 掌握 Oracle 分页、删除重复记录的方法

SQL语句的执行顺序

常见的selectfromwhere的顺序:

1, from  2, where  3, select


完整的selectfromwheregroup byhavingorder by的顺序:

1, from  2, where  3, group by  4,having  5, select  6, order by

EXISTS 的使用

EXISTS用来判断查询所得的结果中,是否有满足条件的纪录存在。

select * from student 
   where    exists(select * from address
                    where zz='郑州');

​ 从select 、from、where三者的先后执行顺序来分析。

在这里插入图片描述

子查询的使用

create table student(sno number(6) ,birthday date, sname varchar2(10));
insert into student values(1, '11-1月-81' , '张三');
insert into student values(2, '10-3月-82' , '李四');
insert into student values(3, '06-1月-83' , '王五');
insert into student values(4, '26-1月-83' , '赵六');


create table address(sno number(6) , zz varchar2(10));
insert into address values(1,   '郑州');
insert into address values(2,   '开封');
insert into address values(3,   '洛阳');
insert into address values(4,   '郑州');

要求:找出zz是郑州的学生中,sno最大的学生的 sname

select sname      
  from student     
 where sno =(        
 select max(sno)              
 from address                
where zz= '郑州' );  

group by的使用
1.创建student表
  create table student(xh number,xm varchar2(10),nl int);
   insert into student values (1,'A',21);  
  insert into student values (2,'B',22);
  insert into student values (3,'A',23);  
  insert into student values (4,'A',24);
  insert into student values (5,'A',25);  
  insert into student values (6,'C',26);
  insert into student values (7,'B',27);

任务:查找xm有相同的纪录,并显示出来,如下

在这里插入图片描述

答案:select * from student where xm in (select xm from student group by xm having count(*)>1);

自连接的使用

CREATE TABLE  管理人员  (
  编号  char(10) ,
  姓名  varchar2(10) ,
  管理人员编号  char(10)
);

insert into 管理人员 values('001', '张一', '004');
insert into 管理人员 values('002', '张二', '004');
insert into 管理人员 values('003', '张三', '003');
insert into 管理人员 values('004', '张四', '004');

要求:现在想显示:编号,姓名,管理人员姓名

select a.编号,a.姓名,b.姓名 as 管理人员姓名    
from 管理人员 a   join 管理人员 b on a.管理人员编号=b.编号;

SELECT CASE WHEN

语法:
CASE    WHEN   条件1   THEN   action1   
		WHEN   条件2   THEN   action2
        WHEN   条件3   THEN   action3
        …..   
        ELSE actionN 
        
        END CASE   

select  case 
      when  substr('20090310',5,2) = '01'  then  '一月份'
      when  substr('20090310',5,2) = '02'  then  '二月份'
      when  substr('20090310',5,2) = '03'  then  '三月份'
      when  substr('20090310',5,2) = '04'  then  '四月份'
      else null
    end 
from dual;
语法:
CASE selector   
		WHEN value1 THEN action1
        WHEN value2 THEN action2
      	WHEN value3 THEN action3
        …..
        
        ELSE actionN
        END [CASE]

select  case substr('20090310',5,2) 
      when   '01'  then  '一月份'
      when    '02'  then  '二月份'
      when   '03'  then  '三月份'
      when    '04'  then  '四月份'
      else null
    end 
from dual;

create table 成绩(sno number, km varchar2(10), score number,grade char(6));     
insert into  成绩 values(1, '语文', 65,null);
insert into  成绩 values(2, '数学', 76,null);
insert into  成绩 values(3, '英语', 86,null);
insert into  成绩 values(4, '语文', 94,null);

要求:把每个学生的grade列,用相应的等级来更新。


update 成绩 set grade = (
   select grade from (
       select sno ,
       case  when  score >= 90 then '优秀'
             when  score >= 80 then '良好'
             when  score >= 70 then '中等'
             when  score >= 60 then '及格' 
             else  '不及格'
       end grade
       from 成绩
     ) a
    where 成绩.sno = a.sno   );


复杂更新语句的使用

表T1里有 a,b,c...N个字段,表T2里有 a,b,c三个字段,
然后想在T1中"c"与表T2中"c"相同的情况下从表T2中将a,b覆盖表T1中的a,b怎么做 ?

 create table T1(a  int ,b int ,c int ,d int ,e int);
 create table T2(a int ,b int ,c int );

 insert into T1 values(1,2,3,4,5);
 insert into T1 values(10,20,3,4,5);
 insert into T1 values(10,20,4, 40,50);
 insert into T2 values( -1, -1 , 3);
 insert into T2 values( -2, -2, 4);


update t1 set a= (select a from t2 where t1.c= t2.c ) ,  
			  b =(select b from t2 where t1.c= t2.c)  
where  t1.c  in (select c from t2);

分析函数的使用

分析函数用于计算完成聚集的累计排名、序号等

分析函数为每组记录返回多个行

以下三个分析函数用于计算一个行在一组有序行中的排位,序号从1开始

  • ROW_NUMBER 返回连续的排序,不论值是否相等

在这里插入图片描述

在这里插入图片描述

  • RANK 具有相等值的行排序相同,序数随后跳跃

在这里插入图片描述

  • DENSE_RANK 具有相等值的行排序相同,序号是连续的

在这里插入图片描述

DECODE 的使用

DECODE 中的if-then-else逻辑
  • 在逻辑编程中,经常用到If – Then –Else 进行逻辑判断。在DECODE的语法中,实际上就是这样的逻辑处理过程。它的语法如下:
  • DECODE(value, if1, then1, if2,then2, if3,then3, . . . else )
  • Value 代表某个表的任何类型的任意列或一个通过计算所得的任何结果。当每个value值被测试,如果value的值为if1,Decode 函数的结果是then1;如果value等于if2,Decode函数结果是then2;等等。事实上,可以给出多个if/then 配对。如果value结果不等于给出的任何配对时,Decode 结果就返回else 。
  • 需要注意的是,这里的if、then及else 都可以是函数或计算表达式。
Create table student(id number,name varchar2(10),sex char(1));
Insert into student values(1, '张', '1');
Insert into student values(2,  '王', '2');
Insert into student values(3, '李', '1');

Select name ,decode(sex, '1','男生', '2','女生') 
from student;case实现:

select id,name,
     case sex
      when '1' then '男'
      when '2' then '女'
     end 性别
from student;



DECODE 取出一行内两列中的较大值
Create table sales(month char(2),sales_tv number,sales_computer number);
 Insert into sales values('01', 10, 18);
 Insert into sales values('02', 28, 20);
 Insert into sales values('03', 36, 33);



select month, decode(sign(sales_tv -sales_computer), 1, sales_tv, sales_computer) as  较大销售量 from sales; 


Oracle中的行列转换

create table 销售(商品名称 varchar2(10), 季度 char(2), 销售额 number);
insert into 销售 values('电视机', '01', 100);
insert into 销售 values('电视机', '02', 200);
insert into 销售 values('电视机', '03', 300);
insert into 销售 values('空调', '01', 50);
insert into 销售 values('空调', '02', 150);
insert into 销售 values('空调', '03', 180);

在这里插入图片描述

从格式1到格式2select a.商品名称,
     sum(decode(a.季度,'01', a.销售额 ,0  ))  一季度,
     sum(decode(a.季度,'02', a.销售额 ,0  ))  二季度,
     sum(decode(a.季度,'03', a.销售额 ,0  ))  三季度,
     sum(decode(a.季度,'04', a.销售额 ,0  ))  四季度
     from 销售 a 
     group by a.商品名称 
     order by 1;

在这里插入图片描述

在这里插入图片描述

ROWNUM 的使用

创建yggz表
 create table yggz (
  bh number(6)   ,
  gz number
  );

insert into yggz values(1,1000);
insert into yggz values(2,1100);
insert into yggz values(3,900);
insert into yggz values(4,2000);
insert into yggz values(5,1500);
insert into yggz values(6,3000);
insert into yggz values(7,1400);
insert into yggz values(8,1200);

在这里插入图片描述

作用:对查询结果,输出前若干条记录
注意:只能与==<<===、between and连用

在这里插入图片描述

任务(1)答案:
    select bh,gz 
from (
  select yggz.*, rownum rn
  from yggz 
)
where rn >=3 and rn <= 5;
或者:
select * from yggz where rownum<=5
minus 
select * from yggz where rownum<=2;

在这里插入图片描述

任务(2)答案:
     select bh,gz from (
 select a.*,rownum rn from(
  select yggz.*    from yggz order by gz desc  ) a 
 )
 where rn<=5 and rn>2;
或者:
 select * from (select * from yggz
      order by gz desc)       where rownum<=5
 minus
 select * from (select * from yggz
      order by gz desc)      where rownum<=2;

在这里插入图片描述

删除重复记录

删除重复记录 方法1
create table student(sno number(6)  , sname varchar2(10), sage  int );  
insert into student values(1, 'AA', 21);
insert into student values(2, 'BB', 22);
insert into student values(3, 'CC', 23);
insert into student values(3, 'CC', 34);
insert into student values(3, 'CC', 35);
insert into student values(3, 'CC', 36);



DELETE FROM student
   WHERE sno IN 
     (SELECT sno FROM student GROUP BY sno HAVING COUNT(*) > 1)
   AND ROWID NOT IN
     (SELECT MIN(ROWID) FROM student GROUP BY sno HAVING COUNT(*) > 1);


删除重复记录 方法2
DELETE FROM student WHERE ROWID IN
    (SELECT A.ROWID FROM student A,student B 
     WHERE A.sno=B.sno AND A.ROWID > B.ROWID);


删除重复记录 方法3
DELETE FROM student d WHERE d.rowid > 
    (SELECT MIN(x.rowid) FROM student x WHERE d.sno=x.sno);

GROUP BY GROUPING SETS

可以用GROUP BY GROUPING SETS来进行分组自定义汇总,**可以应用它来指定你需要的总数组合。

其格式为:
GROUP BY GROUPING SETS ((list), (list) … )

这里(list)是圆括号中的一个列序列,这个组合生成一个总数。要增加一个总和,必须增加一个(NUlL)分组集。

例如:对于scott.emp表,如果要查询:各部门sal大于2000的员工,进行汇总,得到各部门的sal总和、以及总共的sal总和。
SELECT CASE       
   WHEN a.deptno IS NULL THEN
           '合计'
   WHEN a.deptno IS NOT NULL AND a.empno IS NULL THEN
          '小计'
   ELSE
         '' || a.deptno
   END deptno,
      a.empno,        a.ename,
     SUM(a.sal) total_sal
  FROM scott.emp a  WHERE a.sal > 2000  GROUP BY GROUPING SETS((a.deptno),(a.deptno, a.empno, a.ename),());
 

在这里插入图片描述

在这里插入图片描述

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值