03-oracle中的高级查询

1.连接查询

1.1 使用连接谓词指定的连接

介绍:

在连接谓词表示形式中,连接条件由比较运算符在WHERE子句中给出,将这种表示形式称为连接谓词表示形式,连接谓词又称为连接条件。

语法:

[<表名1.>] <列名1> <比较运算符> [<表名2.>] <列名2>

说明:

在连接谓词表示形式中,FROM子句指定需要连接的多个表的表名,WHERE子句指定连接条件,比较运算符有:<、<=、=、>、>=、!=、<>、!<、!>。
由于连接多个表存在公共列,为了区分是哪个表中的列,引入表名前缀指定连接列。例如,student.sno表示student表的sno列,score.sno表示score表的sno列。为了简化输入,SQL允许在查询中使用表的别名,可在FROM子句中为表定义别名,然后在查询中引用。

1.1.1 等值连接

介绍:

表之间通过比较运算符“=”连接起来,称为等值连接

示例:

查询学生的情况和选修课程的情况

SELECT student.*, score.*
  FROM student, score
  WHERE student.sno=score.sno;

1.1.2 自然连接

介绍:

在目标列中去除相同的字段名,称为自然连接

示例:

查询学生的情况和选修课程的情况

SELECT student.*, score.cno, score.grade
  FROM student, score
  WHERE student.sno=score.sno;

手动去除student与score表中都有的sno字段

1.1.3 自连接

介绍:

将同一个表进行连接,称为自连接

示例:

查询选修了“1201”课程的成绩高于学号为“121002”的成绩的学生姓名。

select a1.* from score a1,score a2 
  where a1.cno='1201' and a2.cno='1201' and a2.sno='121002' and   a1.grade>a2.grade;

1.2 使用JOIN关键字指定的连接

语法:

<表名> <连接类型> <表名> ON <条件表达式>
| <表名> CROSS JOIN <表名>
| <连接表>

其中,的格式为:

<连接类型>::=
      [ INNER | { LEFT | RIGHT | FULL } [ OUTER ] CROSS JOIN

说明:
在以JOIN关键字指定连接的表示方式中,在FROM子句中用JOIN关键字指定连接的多个表的表名,用ON子句指定连接条件。
在连接类型中,INNER表示内连接,OUTER表示外连接,CROSS表示交叉连接,这是 JOIN关键字指定的连接的3种类型。

1.2.1 内连接

介绍:
内连接按照ON所指定的连接条件合并两个表,返回满足条件的行。
内连接是系统默认的,可省略INNER关键字。
示例:

查询学生的情况和选修课程的情况。

SELECT *
  FROM student INNER JOIN score ON student.sno=score.sno;

查询选修了数据库系统课程且成绩在84分以上的学生情况。

select st.sno,st.sname,co.cname,sc.grade 
  from student st JOIN score sc ON st.sno=sc.sno JOIN course co ON sc.cno=co.cno 
  where co.cname='数据库系统' and sc.grade>=84;

该语句采用多表内连接,省略INNER关键字

1.2.2 外链接

介绍:
在内连接的结果表,只有满足连接条件的行才能作为结果输出。外连接的结果表不但包含满足连接条件的行,还包括相应表中的所有行。外连接有以下3种:

  1. 左外连接(LEFT OUTER JOIN):结果表中除了包括满足连接条件的行外,还包括左表的所有行。
  2. 右外连接(RIGHT OUTER JOIN):结果表中除了包括满足连接条件的行外,还包括右表的所有行。
  3. 完全外连接(FULL OUTER JOIN):结果表中除了包括满足连接条件的行外,还包括两个表的所有行。

(1)左外连接

示例:

采用左外连接查询教师任课情况。

SELECT teacher.tname, course.cname
  FROM teacher LEFT JOIN course ON (teacher.tno=course.tno);

(2)右外连接

示例:

采用右外连接查询教师任课情况。

SELECT teacher.tname, course.cname
  FROM teacher RIGHT JOIN course ON (teacher.tno=course.tno);

(3)全外连接

示例:

采用全外连接查询教师任课情况。

SELECT teacher.tname, course.cname
  FROM teacher FULL JOIN course ON (teacher.tno=course.tno);

1.2.3 交叉连接

示例:

采用交叉连接查询教师和课程所有可能组合。

SELECT teacher.tname,course.cname
  FROM teacher CROSS JOIN course;

2.集合查询

介绍:
集合查询将两个或多个SQL语句的查询结果集合并起来,利用集合进行查询处理以完成特定的任务,使用四个集合操作符(Set Operator) UNION、UNION ALL、INTERSECT和MINUS,将两个或多个SQL查询语句结合成一个单独SQL查询语句。

集合操作符的功能:

语法:

<SELECT查询语句1>
{UNION | UNION A LL | INTERSECT | MINUS}
<SELECT查询语句2>

说明:

在集合查询中,需要遵循的规则为:

  1. 在构成复合查询的各个单独的查询中,列数和列的顺序必须匹配,数据类型必须兼容。
  2. 用户不许在复合查询所包含的任何单独的查询中使用ORDER BY子句。
  3. 用户不许在BLOB、LONG等大数据对象上使用集合操作符。
  4. 用户不许在集合操作符SELECT列表中使用嵌套表或者数组集合。

2.1 并 UNION

介绍:

UNION语句将第一个查询中的所有行与第二个查询的所有行相加,消除重复行并且返回结果。

示例:

查询所有女教师和女学生的姓名、性别和出生日期。

SELECT tname, tsex, tbirthday
  FROM teacher
  WHERE tsex='女'
UNION
SELECT sname, ssex, sbirthday
  FROM student
  WHERE ssex='女';

2.2 并 UNION ALL

介绍:

UNION ALL语句将第一个查询中的所有行与第二个查询的所有行相加,UNION ALL不会从列表中滤除重复行。

示例:

查询性别为女及选修了课程号为4002的学生,不滤除重复行。

SELECT sno, sname, ssex
  FROM student
  WHERE ssex='女'
UNION ALL
SELECT a.sno, a.sname, a.ssex 
  FROM student a, score b
  WHERE a.sno=b.sno AND b.cno='4002';

2.3 交 INTERSECT

介绍:

INTERSECT操作会获取两个查询,对值进行汇总,并且返回同时存在于两个结果集中的行。

示例:

查询既选修了课程号为8001又选修了课程号为4002的学生的学号、姓名、性别。

SELECT a.sno AS 学号, a.sname AS 姓名, a.ssex AS 性别
  FROM student a, score b
  WHERE a.sno=b.sno AND b.cno='8001'
INTERSECT
SELECT a.sno AS 学号, a.sname AS 姓名, a.ssex AS 性别
  FROM student a, score b
  WHERE a.sno=b.sno AND b.cno='4002';

查询既选修了课程名含有”数据库”又选修了课程名含有”数学”且性别为”男”的学生的学号、姓名、性别和班号。

SELECT a.sno AS 学号, a.sname AS 姓名, a.ssex AS 性别, a.sclass AS 班号
  FROM student a, course b, score c
  WHERE a.sno=c.sno AND b.cno=c.cno AND b.cname like '%数据库%' AND a.ssex='男'
INTERSECT
SELECT a.sno AS 学号, a.sname AS 姓名, a.ssex AS 性别, a.sclass AS 班号
  FROM student a, course b, score c
  WHERE a.sno=c.sno AND b.cno=c.cno AND b.cname like '%数学%' AND a.ssex='男';

2.4 差 MINUS

介绍:

MINUS集合操作会返回所有从第一个查询中有但是第二个查询中没有的那些行。

示例:

查询既选修了课程号为8001又未选修课程号为4002的学生的学号、姓名、性别。

SELECT a.sno AS 学号, a.sname AS 姓名, a.ssex AS 性别
  FROM student a, score b
  WHERE a.sno=b.sno AND b.cno='8001'
MINUS
SELECT a.sno AS 学号, a.sname AS 姓名, a.ssex AS 性别
  FROM student a, score b
  WHERE a.sno=b.sno AND b.cno='4002';

查询既选修了英语又未选修数字电路的学生的姓名、性别、出生日期和班号。

SELECT a.sname AS 姓名, a.ssex AS 性别, a.sbirthday AS 出生日期, a.sclass AS 班号
  FROM student a, course b, score c
  WHERE a.sno=c.sno AND b.cno=c.cno AND b.cname='英语' 
MINUS
SELECT a.sname AS 姓名, a.ssex AS 性别, a.sbirthday AS 出生日期, a.sclass AS 班号
  FROM student a, course b, score c
  WHERE a.sno=c.sno AND b.cno=c.cno AND b.cname='数字电路';

3.子查询

介绍:
使用子查询,可以用一系列简单的查询构成复杂的查询,从而增强SQL语句的功能。
在SQL语言中,一个SELECT-FROM-WHERE语句称为一个查询块。在WHERE子句或HAVING子句所指定条件中,可以使用另一个查询块的查询的结果作为条件的一部分,这种将一个查询块嵌套在另一个查询块的子句指定条件中的查询称为嵌套查询。例如:

SELECT * 
  FROM student
  WHERE sno IN
    (SELECT sno 
       FROM score 
       WHERE cno='1004'
     );

下层查询块“SELECT stno FROM score WHERE cno='203'”的查询结果,作为上层查询块“SELECT * FROM student WHERE stno IN”的查询条件,上层查询块称为父查询或外层查询,下层查询块称为子查询(Subquery)或内层查询,嵌套查询的处理过程是由内向外,即由子查询到父查询,子查询的结果作为父查询的查询条件。

3.1 IN子查询

介绍:
在IN子查询中,使用IN谓词实现子查询和父查询的连接。
语法:

<表达式> [ NOT ] IN ( <子查询>)

说明:
在IN子查询中,首先执行括号内的子查询,再执行父查询,子查询的结果作为父查询的查询条件。
当表达式与子查询的结果集中的某个值相等时,IN谓词返回TRUE,否则返回FALSE;若使用了NOT,则返回的值相反。
示例:

查询选修了课程号为8001的课程的学生情况。

SELECT * 
FROM student
WHERE sno IN
  (SELECT sno 
    FROM score 
    WHERE cno='8001' 
   );

查询未选修数字电路课程的学生情况。

select * from student where sno NOT IN
  (select sno from score where cno in
    (select cno from course where cname='数字电路'));

查询选修某课程的学生人数多于4人的教师姓名。

select teacher.tname from teacher where tno in
(select tno from course where cno in
  (select cno from score GROUP BY cno HAVING count(sno)>=4));

查询在计算机专业任课的教师情况。

select teacher.* from teacher where tno in
  (select c.tno from student a,score b,course c 
    where a.sno=b.sno and b.cno=c.cno and a.speciality='计算机');

3.2 比较子查询

介绍:

比较子查询是指父查询与子查询之间用比较运算符进行关联。

语法:

<表达式> { < | <= | = | > | >= | != | <>  } { ALL | SOME | ANY } ( <子查询> )

说明:
关键字ALL、SOME和ANY用于对比较运算的限制,ALL指定表达式要与子查询结果集中每个值都进行比较,当表达式与子查询结果集中每个值都满足比较关系时,才返回TRUE,否则返回FALSE;SOME和ANY指定表达式要只与子查询结果集中某个值满足比较关系时,就返回TRUE,否则返回FALSE。

3.2.1 ALL

示例:

查询比所有计算机专业学生年龄都小的学生。

SELECT *
  FROM student
  WHERE sbirthday >ALL
    (SELECT sbirthday 
       FROM student  
       WHERE speciality='计算机'
    );

3.2.2 ANY SOME

示例:

查询课程号8001的成绩高于课程号4002成绩的学生。

select * from score where cno='8001' and grade> ANY(select grade from score where cno='4002');
select * from score where cno='8001' and grade> SOME(select grade from score where cno='4002');

ANY与SOME用法和结果一模一样

3.3 EXISTS子查询

介绍:
在EXISTS子查询中,EXISTS谓词只用于测试子查询是否返回行,若子查询返回一个或多个行,则EXISTS返回TRUE,否则返回FALSE,如果为NOT EXISTS,其返回值与EXIST相反。
语法:

[ NOT ] EXISTS ( <子查询> )

说明:
在EXISTS子查询中,父查询的SELECT语句返回的每一行数据都要由子查询来评价,如果EXISTS谓词指定条件为TRUE,查询结果就包含该行,否则该行被丢弃。

示例:

查询选修1004课程的学生姓名。

SELECT sname AS 姓名
  FROM student
  WHERE EXISTS 
    (SELECT *
       FROM score
       WHERE score.sno=student.sno AND cno='1004'
     );

4.综合训练

(1)查询选修数据库系统课程的学生的姓名、性别、班级和成绩。

select a.sname,a.ssex,a.sclass,b.grade from student a,score b,course c 
  where a.sno=b.sno and b.cno=c.cno and c.cname='数据库系统';

(2)查找选修了8001课程且为计算机专业学生的姓名及成绩,查出的成绩按降序排列。

select a.sname,b.grade from student a,score b 
  where a.sno=b.sno ORDER BY b.grade DESC;

(3)查询既选修了英语又未选修数据库系统的学生的学号、姓名、出生日期和专业。

select a.sno,a.sname,a.sbirthday,a.speciality from student a,score b,course c
  where a.sno=b.sno and b.cno=c.cno and c.cname='英语'
MINUS
select a.sno,a.sname,a.sbirthday,a.speciality from student a,score b,course c
  where a.sno=b.sno and b.cno=c.cno and c.cname='数据库系统';

(4)查找学号为124001,课程名为”高等数学”的学生成绩。

select grade from score b,course c
  where b.cno=c.cno and c.cname='高等数学' and b.sno='124001';
select score.grade from score JOIN course ON score.cno=course.cno 
  where course.cname='高等数学' and score.sno='124001'; 
select * from score 
  where sno='124001' and cno in (select cno from course where cname='高等数学');

5.应用题

(1)查询选修了“英语”的学生姓名及成绩。

select a.sname,b.grade from student a,score b,course c 
  where a.sno=b.sno and b.cno=c.cno and c.cname='英语';

(2)查询选修了“高等数学”且成绩在80分以上的学生情况。

select a.sname as 学生姓名,b.grade as 分值 from student a,score b,course c 
  where a.sno=b.sno and b.cno=c.cno and c.cname='高等数学' and b.grade>=80;

(3)查询选修某课程的平均成绩高于85分的教师姓名。

select tname from teacher where tno in
  (select tno from course where cno in
    (select cno from score GROUP BY cno HAVING avg(grade)>=85)); 

(4)查询既选修了‘1201’号课程,又选修过‘1004’号课程的学生姓名、性别和总学分。

select a.sname,a.ssex,a.tc
  from student a, score b where a.sno=b.sno and b.cno='1201'
intersect
select sname,ssex,tc 
  from student where sno in(select sno from score where cno='1004');

(5)查询既选修了‘1201’号课程,又未选修过‘1004’号课程的学生姓名、性别和总学分。

select a.sname,a.ssex,a.tc
    from student a, score b where a.sno=b.sno and b.cno='1201'
MINUS
select sname,ssex,tc 
    from student where sno in(select sno from score where cno='1004');

(6)查询每个专业最高分的课程名和分数。

select c.cname,d.maxgrade 
  from course c,(select cno,MAX(grade) maxgrade from score GROUP BY cno) d where c.cno=d.cno;

(7)查询通信专业的最高分。

思路:
1.选修通信专业的学生
​ select distinct b.sno from student a,score b where a.sno=b.sno and a.speciality='通信'
2.选修通信专业的学生的所有成绩
select * from score
​ where sno in (select distinct b.sno from student a,score b where a.sno=b.sno and a.speciality='通信');
3.选修通信专业的最高分

select MAX(grade) as 通信专业的最高成绩  from score 
      where sno in (select distinct b.sno from student a,score b where a.sno=b.sno and a.speciality='通信');
select max(grade) as 最高分 
  from student a,score b 
  where a.sno=b.sno and a.speciality='通信' GROUP BY a.speciality;

(8)查询数据库系统课程的任课教师名称。

select teacher.* from teacher where tno in
  (select c.tno from course c where c.cname='数据库系统');

(9)查询学生成绩高于平均分的学号,课程号及成绩。

select sno as 学号,cno as 课程号,grade as 成绩 from score 
  where grade >(select AVG(grade) from score) ;

(10)查询既选修了课程名含有”数据库”又选修了课程名含有”数学”且性别为”男”的学生的学号、姓名、性别和班号。

select a.sno,a.sname,a.ssex,a.sclass 
  from student a JOIN score b ON a.sno=b.sno JOIN course c ON b.cno=c.cno 
  where c.cname like '%数据库%' and a.ssex='男'
INTERSECT
select a.sno,a.sname,a.ssex,a.sclass 
  from student a JOIN score b ON a.sno=b.sno JOIN course c ON b.cno=c.cno 
  where c.cname like '%数学%' and a.ssex='男';

(11)查询出每个部门的编号、名称、位置、部门人数、平均工资。

思路:
1.根据员工表查询部门编号、部门人数和平均工资
select deptno,COUNT(*) as deptTotal,AVG(sal) as avgSal from emp GROUP BY deptno
2.根据部门编号查询具体的部门信息

select a.deptno 编号,a.dname 名称,a.loc 位置,b.depttotal 平均工资,b.avgsal 平均工资 from dept a, 
  (select deptno,COUNT(*) as deptTotal,AVG(sal) as avgSal from emp GROUP BY deptno) b where a.deptno=b.deptno;

(12)找出其它部门比20号部门某员工工资高的雇员信息。

思路:
1.查询20号部门的所有工资
select sal from emp where deptno='20';
2.查询不在20号部门的员工工资任意大于(1)
*/

select * from emp where deptno NOT IN (20) and sal > SOME (select sal from emp where deptno='20');

(13)查询员工工资在MANAGER职位工资范围的员工信息。

select * from emp where job !='MANAGER' and 
  sal >=(select MIN(sal) minSal from emp where job ='MANAGER');

(14)查询高出公司平均工资的全部雇员的信息。

select * from emp where sal >= (select AVG(sal) avgSal from emp);

(15)查询与SMITH在同一部门的员工信息。

select * from emp where ename !='SMITH' and deptno = (select deptno from emp where ename='SMITH');

转载于:https://www.cnblogs.com/gj-blog/p/10671923.html

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值