当前位置:   article > 正文

Oracle-第一章-多表查询和其他_oracle 关联查询 默认是inner

oracle 关联查询 默认是inner

4多表关联查询

4.1表的别名

  1. ①在多表关联查询时,如果多个表之间存在同名的列,则必须用表名限定列的引用
  2. 如dept.deptno,emp.deptno
  3. ②为使语句简洁,使用表别名,表别名在from子句中定义如 emp e
  4. ③表别名一经定义,在整个查询语句中就只能用表别名,而不能用表名 emp.ename × e.ename √
  5. ④表别名只在所定义的查询语句中有效

4.2内连接(直连-只显示关联到的结果,会遗失部分数据)

  1. ####
  2. select d.dormno, s.name
  3. from dorm d
  4. [inner]join student s--默认是inner内查询,不用写
  5. on d.id=s.dormid;
  6. --用相同的ID来进行表之间连接
  7. ####
  8. select b.buildname,d.dormno,s.name
  9. from building b
  10. join dorm d
  11. on b.id = d.buildid
  12. join student s
  13. on d.id = s.dormid;
  14. --三个及以上连接
  15. ####
  16. select d.dormno, s.name
  17. from dorm d
  18. join student s
  19. on d.id = s.dormid
  20. where s.gender = ;
  21. --条件语句放在后面
  22. ####
  23. 内连接的另一种写法(了解即可,千万别用)
  24. select e.ename,d.dname,e.sal
  25. from emp e,dept d--省去了join on 语句
  26. where sal>=3000;--忘记写where子句会导致笛卡尔积任意关联,会导致非常严重的数据库崩溃
  27. --笛卡尔积:两个表做任意关联,无关联条件,导致数据暴增

4.3外连接(可以返回不相关的数据行,不必须有条件语句)

(1)左连接(以左边的为主表,显示所有行的结果,以右边的为从表,只显示关联的结果)

  1. select e.ename,d.dname,e.comm
  2. from dept d
  3. left join emp e
  4. on e.deptno=d.deptno;--此处应该在建表时用id而不用no
  5. ####
  6. select s.name,d.dormno
  7. from student s, dorm d
  8. where s.dormid=d.id(+);
  9. --左连接另种写法,仅作了解,千万别用,会造成笛卡尔积数据库崩溃或数据丢失
  10. ####
  11. ▲如果左连接的从表添加where条件,则左连接失效
  12. 例:查询所有人的姓名,如果其他宿舍在2楼,显示宿舍号
  13. select s.name,d.dormno
  14. from student s
  15. left join dorm d
  16. on d.id=s.dormid
  17. where d.floor=2;--此处where应改为and,把选择条件变成关联条件

(2)右连接

right用法和左连接一样

(3)全连接(特殊情况才用,一般不用,显示左右全部数据,如果关联则在同一行)

full同上

4.4自然连接(几乎不用)

  1. 自然连接指在检索多个表时
  2. oracle会将个表中的列和第二个表中具有相同名称的列进行自动连接
  3. 语法: natural join
  4. select empno,ename,job,dname
  5. from emp
  6. natural join dept
  7. where sal>2000;
  8. --由于自然连接要求表之间必须有相同名称的列,这样容易在出现不可预知的错,故几乎不用

4.5自连接(一表两用)

  1. ####
  2. select em2.ename 上层管理者,em1.ename 下属员工
  3. from emp em1
  4. join emp em2
  5. on em1.mgr=em2.empno--关键在于找到对应关系
  6. order by em1.mgr;
  7. ####
  8. 如果左连接后使用自连接,则自连接会失效
  9. 例:
  10. select d.dormno,s.name,s1.name
  11. from student s
  12. left join dorm d
  13. on d.id=s.dormid
  14. left join student s1
  15. on d.headno=s1.stuno;
  16. --仅作语法示例

4.6交叉连接(几乎不用,会造成笛卡尔积)

  1. 语法: cross join
  2. select count(*) --计算查询结果的行数
  3. from dept
  4. cross join emp;
  5. --执行结果是一个笛卡尔积
  6. 等同于
  7. select count(*)
  8. from dept,emp;
  9. --执行结果是一个笛卡尔积

5子查询

  1. 又称嵌套查询
  2. 在执行数据操作时
  3. 某个操作要依赖另一个select语句的查询结果
  4. 可以select语句嵌入该语句中
  5. 注意:
  6. ①子查询子句必须用括号括起来
  7. ②子查询不能包括order by
  8. ③子查询允许多层(不超过255行)嵌套
  9. ④子查询比多表关联查询更灵活、功能更强大、更容易理解,但效率更低

5.1单行子查询

  1. 指子查询语句的返回结果只有一行
  2. 当在where子句中引用单行子查询时可以用单行比较运算符(= > < >= <= <>
  3. ①关联子查询在select语句(查询结果中)
  4. select s.name,s.gender,s.groupno,
  5. (select avg(t.age)from student t)--此处的平均年龄只作为常量,不是聚合函数
  6. from student s;
  7. --查询每个人的姓名、年龄和班级平均年龄
  8. ②关联子查询在条件语句中
  9. select empno, ename, sal--外查询
  10. from emp
  11. where sal > (select min(sal) from emp)--括号内是内查询
  12. and sal < (select max(sal) from emp);
  13. --查询emp表中不是高或低工资的员工编号、姓名、工资

5.2多行子查询

  1. 指子查询语句的返回结果不止一行
  2. 当在where子句中引用多行子查询时必须用多行比较符(in any all

(1.1)in运算符

  1. 在多行子查询中使用in运算符时
  2. 外查询会尝试与子查询结果中任何一个结果进行匹配
  3. 只要有一个匹配成功则外查询会返回当前的检索记录
  4. select empno,ename,job
  5. from emp
  6. where deptno in
  7. (select deptno from dept where dname<>'SALES');
  8. --查询emp表中不是销售部门的员工信息

(1.2)exists运算符

  1. exists存在(前面可以加not
  2. --查询有预备党员的小组
  3. select s.groupno
  4. from student s
  5. where s.groupno in
  6. select t.groupno
  7. from student t
  8. where t.political = '预备党员');
  9. select distinct s.groupno
  10. from student s
  11. where exists (select t.groupno
  12. from student t
  13. where t.political = '预备党员'
  14. and s.groupno = t.groupno);
  15. --查询没有预备党员的小组
  16. select distinct s.groupno
  17. from student s
  18. where not exists (select t.groupno
  19. from student t
  20. where t.political = '预备党员'
  21. and s.groupno = t.groupno);
  22. 工作中常用 exists代替 in(速度更快)
  23. in关联子查询先子查询全部
  24. 再主查询(速度慢,但容易想)
  25. exists:关联子查询先主查询一条一条查询
  26. 再子查询(子查询不需要查询全部,速度更快)
  27. ①将原 SQLin改为 exists
  28. ②在子查询中添加条件
  29. (原子查询的结果=原主查询中 in的前面一致)

(2)any运算符

  1. any运算符必须与单行操作符结合使用
  2. 并且返回行只要匹配子查询的任何一个结果即可
  3. select deptno,ename,sal
  4. from emp
  5. where
  6. sal>any (select sal from emp where deptno=30)
  7. and deptno<>30;--and与sal语句是并列的
  8. --查询emp表中工资大于30号部门的任意一个员工工资的其他部门的员工信息
  9. --实质上查询emp表中工资大于30号部门的低的一个员工工资的其他部门的员工信息

(3)all运算符

  1. all运算符必须与单行操作符结合使用
  2. 并且返回行必须匹配子查询的所有结果
  3. select deptno,ename,sal
  4. from emp
  5. where
  6. sal>all (select sal from emp where deptno=30);
  7. ----查询emp表中工资大于30号部门的所有员工工资的其他部门的员工信息
  8. --与any相比较

5.3多列子查询

  1. select *
  2. from student s
  3. where (s.age,s.gender)=(select t.age,t.gender from student t where name='张简简');
  4. --查询年龄和性别都和张简简相同的人
  5. --注意s.age,s.gender和t.age,t.gender前后顺序要一致

5.4关联子查询

  1. 在单行或多行子查询中内查询和外查询是分开执行的
  2. 外查询仅仅使用内查询的终结果
  3. 在一些特殊需求的子查询中内查询和外查询相互关联
  4. 被称为关联子查询
  5. ①关联子查询在select语句(查询结果中)
  6. select s.name,s.gender,s.groupno,
  7. (select avg(t.age)from student t where t.groupno=s.groupno)
  8. from student s;
  9. --使用了两个表别名
  10. --不需要使用分组函数
  11. --例 select avg(t.age) from student t where t.groupno*=1
  12. 即可查询1组的平均年龄
  13. ②关联子查询在条件语句中
  14. select s.name,s.age
  15. from student s
  16. where s.age>(select avg(t.age) from student t where t.groupno=s.groupno);
  17. --查询比小组平均年龄大的人

5.5子查询难点用法

  1. --查询A型血人数比B型血人数多的宿舍
  2. select ssaxx.dormno
  3. from (select d.dormno,count(1) ssaxxrs
  4. from student s
  5. join dorm d
  6. on s.dormid=d.id
  7. where s.xo='A'
  8. group by d.dormno) ssaxx--把A血型的寝室和人数看作一个表
  9. join (select d.dormno,count(1) ssbxxrs
  10. from student s
  11. join dorm d
  12. on s.dormid=d.id
  13. where s.xo='B'
  14. group by d.dormno) ssbxx--把B血型的寝室和人数看作一个表
  15. on ssaxx.dormno=ssbxx.dormno
  16. where ssaxx.ssaxxrs>ssbxx.ssbxxrs;
  17. --当问题不清晰的时候拆解成多个表来解决问题即可

6 开窗函数

也称分析函数窗,就是范围在over子句所限定的范围内进行查询,速度优于子查询。

6.1 partition by

  1. select s.name,s.groupno,s.age,
  2. max(s.age) over(partition by s.groupno) age1
  3. from student s;
  4. --查询所有同学姓名、组号、年龄和其最大年龄
  5. --partition by 类似于 group by具有分组的作用
  6. --【max(s.age) over(partition by s.groupno) age1】是一个整体
  7. 使用多个聚合函数时每个要单独加over语句
  8. --由于受开窗范围的影响别名(此处为age1)要放在 order by后

6.2 order by

  1. select s.name,s.groupno,s.age,max(s.age)
  2. over(partition by s.groupno order by s.age)
  3. from student s;
  4. --查询所有同学姓名、组号年龄和窗口内大年龄
  5. --order by
  6. 不仅仅具有排序的作用
  7. 只有 order by 没有 partition by 则仅有排序功能
  8. 会使窗口发生变化
  9. 窗口变化为从 partition by选定的窗口的行数据开始
  10. 到与被查询主体 order by后的列名(此处为s.age)相同值的所有数据行为止
  11. (不明白就运行代码试试)

6.3 排序类开窗函数 row_number()、 rank()、dense_rank() 

  1. 在窗口范围内对 order by 后指定的数据进行排序
  2. select s.name,s.groupno,s.age,
  3. row_number() over(partition by s.groupno order by s.age)
  4. from student s;
  5. --相同年龄也分先后顺序
  6. 如:排序 1 2 3 4 5
  7. 年龄 18 19 19 19 20
  8. select s.name,s.groupno,s.age,
  9. rank() over(partition by s.groupno order by s.age)
  10. from student s;
  11. --并列第二然后第五
  12. 如:排序 1 2 2 2 5
  13. 年龄 18 19 19 19 20
  14. select s.name,s.groupno,s.age,
  15. dense_rank() over(partition by s.groupno order by s.age)
  16. from student s;
  17. --并列第二然后第三
  18. 如:排序 1 2 2 2 3
  19. 年龄 18 19 19 19 20

6.4 偏移类开窗函数 lag() lead()

  1. select s.name,s.groupno,s.age,
  2. lag(s.age) over(partition by s.groupno order by s.age)
  3. from student s;
  4. --lad(参数1,参数2,参数3)
  5. 参数1(列名)所处位置的数据往上偏移参数2个位置
  6. 如果偏移后数据为空则用参数3的数据填充
  7. --lead(参数1,参数2,参数3)
  8. 往下偏移

6.5 了解部分

(1)first_value() last_value()

  1. --不可和聚合函数同用
  2. select s.name,s.groupno,s.age,
  3. first_value(s.age) over(partition by s.groupno order by s.age),
  4. last_value(s.name) over(partition by s.groupno order by s.age)
  5. from student s;
  6. --注意要写逗号
  7. --first_value(col_name)返回该窗口中某列的个值
  8. --last_value(col_name)返回该窗口中某列的后一个值

(2)影响开窗范围的参数(range between 参数1 and 参数2)(可以有聚合函数,必须有order by)

  1. range between 参数1 and 参数2
  2. 在原来的窗口范围内再进行选定
  3. select q.realname,q.groupno,q.age,
  4. max(q.age) over(partition by q.groupno order by q.agerange between 参数1 and 参数2)
  5. from qqinfo q;
  6. 参数可以替换为以下:
  7. unbounded preceding 组内首行
  8. current row 当前行
  9. unbounded following 组内末行
  10. 1 preceding 组内当前行前面1
  11. 1 following 组内当前行后面1
  12. range 值比较--不了解
  13. rows 行比较--不了解

7 其他

7.1 查询中的集合操作

  1. 两个集合间 交 并 差
  2. 1)并
  3. union (自带去重效果)
  4. (去重必带排序)
  5. (oracle中去重和排序都非常慢)
  6. union all (不去除重复内容)
  7. (执行速度更快)
  8. 例:
  9. select s.name from student s
  10. union
  11. select e.name from emp e
  12. 此外要注意多列同时运算的情况:
  13. 对应列如s.age和e.age的属性和类型要一致
  14. select s.name,s.age from student s
  15. union
  16. select e.name,e.age from emp e
  17. 2)交( intersect
  18. 3)差 ( minus )

7.2 case when

  1. 查询结果根据类别不同,查询方式随之不同
  2. select s.name,--逗号不能少
  3. case--开始
  4. when s.gender=1 then '男生'
  5. when s.gender= then '女生'--也可以只有一个 when then语句
  6. else '其他'
  7. end--结束
  8. from student s;
  9. 需要注意的是 case when 是顺序执行的
  10. 如果前面的条件包含了后面的条件
  11. 则后面的条件
  12. 如:
  13. select s.name,
  14. case
  15. when s.score>60 then '及格'
  16. when s.score>80 then ''
  17. else '不及格'
  18. end
  19. from student s;
  20. --则60分以上的都是及格,即使是100也是及格而不是
  21. case when 中的条件是确定值(即用等号=)时
  22. 可等价于decode如:
  23. select s.name,--逗号不能少
  24. decode(s.gendere,1,'男生',,'女生','其他')
  25. from student s;

7.3 行列相互转换

(1)行转列【常面】

  1. 将同一列内容分成多列
  2. group by
  3. case when
  4. ③ 聚合函数
  5. 例(查询班内全部人数,男生数量,女生数量):
  6. select count(1),
  7. count(case when s.gender=1 then '是' end) nans,
  8. count(case when s.gender= then '是' end) nvs
  9. from student s;
  10. 例(查询各组全部人数,男生数量,女生数量):
  11. select s.groupno,
  12. count(1),
  13. count(case when s.gender=1 then '是' end) nans,
  14. count(case when s.gender= then '是' end) nvs
  15. from student s
  16. group by s.groupno;

(2)列转行【常面】

  1. 将不同列的内容汇总到同一列
  2. union[all](并-操作)
  3. select name,'男' gender from stul where nans=1
  4. union
  5. select name,'女' from stu1 where nvs=1;

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小小林熬夜学编程/article/detail/425201
推荐阅读
相关标签
  

闽ICP备14008679号