数据准备

表结构

  1. -- 部门表
  2. CREATE TABLE DEPT (
  3. dept_no VARCHAR2(5) NOT NULL,
  4. dept_name VARCHAR2(255) NOT NULL,
  5. PRIMARY KEY(dept_no)
  6. );
  7. -- 添加注释
  8. COMMENT ON TABLE DEPT IS '部门表';
  9. COMMENT ON COLUMN DEPT.dept_no IS '部门编码';
  10. COMMENT ON COLUMN DEPT.dept_name IS '部门名称';
  11. -- 员工表
  12. CREATE TABLE EMP (
  13. emp_no VARCHAR2(8) NOT NULL,
  14. emp_name VARCHAR2(20) NOT NULL,
  15. dept_no VARCHAR2(5) NOT NULL,
  16. salary NUMBER(10, 2),
  17. PRIMARY KEY(emp_no)
  18. );
  19. -- 添加注释
  20. COMMENT ON TABLE EMP IS '员工表';
  21. COMMENT ON COLUMN EMP.emp_no IS '员工编码';
  22. COMMENT ON COLUMN EMP.emp_name IS '员工名称';
  23. COMMENT ON COLUMN EMP.dept_no IS '所属部门编码';
  24. COMMENT ON COLUMN EMP.salary IS '工资';

演示数据

  1. -- 插入部门
  2. insert into DEPT(dept_no, dept_name) values ('D001', '总经理部');
  3. insert into DEPT(dept_no, dept_name) values ('D002', '人力资源部');
  4. insert into DEPT(dept_no, dept_name) values ('D003', '行政后勤部');
  5. insert into DEPT(dept_no, dept_name) values ('D004', '销售一部');
  6. insert into DEPT(dept_no, dept_name) values ('D005', '销售二部');
  7. insert into DEPT(dept_no, dept_name) values ('D006', '研发一部');
  8. insert into DEPT(dept_no, dept_name) values ('D007', '研发二部');
  9. -- 批量插入员工数据
  10. declare
  11. type e_name is varray(7) of varchar2(20);
  12. e_name_arr e_name :=e_name('陈天龙','李晓红','田萌','张三','李四', '王五', '赵六');
  13. begin
  14. for d in 1..7 loop
  15. for i in 1..(d*3) Loop
  16. insert into EMP(emp_no, emp_name, dept_no, salary) values (
  17. 'E' || d || replace(lpad(i,5),' ','0'),
  18. e_name_arr(d) || i || '号',
  19. 'D' || replace(lpad(d,3),' ','0'),
  20. trunc(dbms_random.value(3,80)) * 1000
  21. );
  22. end loop;
  23. end loop;
  24. end;

基本语法

简单的with语句:

  1. WITH t AS
  2. (SELECT * FROM EMP)
  3. SELECT * FROM t;

在视图中使⽤WITH语句进⾏连接:

  1. CREATE OR REPLACE VIEW V_EMP_DETAIL AS
  2. WITH W_DEPT AS (
  3. SELECT * FROM DEPT
  4. ),
  5. W_EMP AS (
  6. SELECT * FROM EMP
  7. )
  8. SELECT d.dept_name, e.*
  9. FROM W_EMP e
  10. LEFT JOIN W_DEPT d ON d.dept_no = e.dept_no;

总结:

  • 使⽤WITH AS 语句可以为⼀个⼦查询语句块定义⼀个名称,在查询语句的其他地⽅引⽤这个⼦查询。

  • Oracle 数据库像对待内联视图或临时表⼀样对待 被引⽤的⼦查询名称,从⽽起到⼀定的优化作⽤

  • 在同级select前有多个查询定义的时候,第1个⽤with,后⾯的不⽤with,并且⽤逗号隔开。

  • 最后⼀个with ⼦句与下⾯的查询之间不能有逗号,只通过右括号分割,with ⼦句的查询必须⽤括号括起来

WITH语句的优点:

  1. SQL可读性增强。⽐如对于特定with⼦查询取个有意义的名字等。
  2. with⼦查询只执⾏⼀次,将结果存储在⽤户临时表空间中,可以引⽤多次,增强性能。

示例

1、查询出部门的总工资⼤于所有部门平均总工资的部门。

分析:做这个查询,⾸先必须计算出所有部门的总工资,然后计算出所有部门的平均总工资,再筛选出部门的总工资⼤于所有部门总工资平均工资的部门。

  1. 那么第1步 with 查询查出所有部门的总工资
  2. 第2步⽤with 从第1 步获得的结果表中查询出平均工资
  3. 最后利⽤这两次 的with 查询⽐较总工资⼤于平均工资的结果
  1. WITH W_DEPT_TOTAL_SALARY AS -- 查询出部门的总⼯资
  2. ( SELECT d.dept_name, SUM(e.salary) total_salary
  3. FROM DEPT d
  4. JOIN EMP e ON e.dept_no = d.dept_no
  5. GROUP BY d.dept_name
  6. ),
  7. W_DEPT_AVG_SALARY AS -- 查询出部门的平均⼯资,在后⼀个WITH语句中可以引⽤前⼀个定义的WITH语句
  8. (
  9. SELECT SUM(total_salary) / COUNT(1) avg_salary
  10. FROM W_DEPT_TOTAL_SALARY
  11. )
  12. SELECT *
  13. FROM W_DEPT_TOTAL_SALARY dts
  14. WHERE dts.total_salary > ( -- 进⾏⽐较
  15. SELECT das.avg_salary
  16. FROM W_DEPT_AVG_SALARY das
  17. );

2. 统计数据并关联到每条员工数据

展⽰根据查询结果查询出的数据,并把根据查询出的结果进⾏统计,如最⼤⼯资,最⼩⼯资,平均⼯资,

进⾏级联,由于查询的统计数据的条数为1条,所以不会发⽣笛卡⼉积的错误,

  1. WITH W_EMP AS -- 查询基础数据
  2. (
  3. SELECT emp_no, emp_name, dept_no, salary
  4. FROM EMP
  5. ),
  6. W_EMP_DATA AS -- 查询统计数据
  7. (
  8. SELECT MAX(salary) as max_salary,
  9. MIN(salary) as min_salary,
  10. SUM(salary) as total_salary
  11. FROM W_EMP
  12. )
  13. SELECT *
  14. FROM W_EMP, W_EMP_DATA -- 进⾏级联,由于查询的统计数据的条数为1条,所以不会发⽣笛卡⼉积的错误

3. 后⾯的with定义可以引⽤前⾯的结果集,但是with⼦查询不可嵌套定义。

下⾯的语句错误:因为不允许嵌套定义with语句

  1. WITH W_EMP_2 AS
  2. -- with中有嵌套with,不允许
  3. (
  4. WITH W_EMP AS
  5. (
  6. SELECT emp_name FROM EMP WHERE emp_no='E100001'
  7. )
  8. SELECT emp_name FROM W_EMP
  9. )
  10. SELECT * FROM W_EMP_2;

递归案例

  1. 实现从1到10的输出

    1. with w_num(n) as (
    2. select 1 as n from dual
    3. union all
    4. select n+1 from w_num where n<10
    5. )
    6. select n from w_num;
  2. 空瓶换啤酒最多能喝几瓶问题

    1. /**
    2. 2元1瓶啤酒
    3. 4个瓶盖换1瓶啤酒
    4. 2个空瓶换1瓶啤酒
    5. 问:10元可以喝几瓶
    6. */
    7. with w_drink_beer(beer, bottle, lid) AS
    8. (
    9. select 10/2 as beer, 10/2 as bottle, 10/2 as lid
    10. from dual
    11. union all
    12. select
    13. beer + trunc(bottle/2) + trunc(lid/4) as beer,
    14. mod(bottle, 2) + trunc(bottle/2) + trunc(lid/4) as bottle,
    15. mod(lid, 4) + trunc(bottle/2) + trunc(lid/4) as lid
    16. from w_drink_beer
    17. where trunc(bottle/2) != 0 or trunc(lid/4) != 0
    18. )
    19. select beer as '喝了几瓶啤酒', bottle as '剩下几个瓶子', lid as '剩下几个瓶盖'
    20. from w_drink_beer;

递归-地铁线路换乘问题

SQL案例分析:地铁换乘线路查询

示例表和脚本下载:https://github.com/dongxuyang1985/sql_in_action

  1. -- Oracle
  2. WITH transfer (start_station, stop_station, stops, path) AS (
  3. SELECT station_name, next_station, 1, line_name||station_name||'->'||line_name||next_station
  4. FROM bj_subway WHERE station_name = '王府井'
  5. UNION ALL
  6. SELECT p.start_station, e.next_station, stops + 1, p.path||'->'||e.line_name||e.next_station
  7. FROM transfer p
  8. JOIN bj_subway e
  9. ON p.stop_station = e.station_name AND (INSTR(p.path, e.next_station) = 0)
  10. )
  11. SELECT * FROM transfer WHERE stop_station ='积水潭';

Oracle with使用方法以及递归的更多相关文章

  1. .NET 基础 一步步 一幕幕[面向对象之方法、方法的重载、方法的重写、方法的递归]

    方法.方法的重载.方法的重写.方法的递归 方法: 将一堆代码进行重用的一种机制. 语法: [访问修饰符] 返回类型 <方法名>(参数列表){ 方法主体: } 返回值类型:如果不需要写返回值 ...

  2. oracle 表迁移方法 (二) 约束不失效

    DB:11.2.0.3.0 在oracle 表迁移方法 (一)中,只是move了一张普通的表,如果表的字段带有主键约束呢 ? [oracle@db01 ~]$ sqlplus / as sysdba ...

  3. 【转】PLSQL developer 连接不上64位Oracle 的解决方法

    PLSQL developer 连接不上64位Oracle 的解决方法 快乐无极 , 2012/06/13 10:10 , 开发文档 , 评论(6) , 阅读(140430) , Via 本站原创 大 ...

  4. .net远程连接oracle数据库不用安装oracle客户端的方法

    .net远程连接oracle数据库不用安装oracle客户端的方法步骤: 1.添加Sytem.Data.OracleClient命名空间. 2.连接时需要ConnectionString字符串,出现在 ...

  5. oracle创建job方法

    oracle创建job方法  alter system enable restricted session;--创建表create table G_TEST ( ID     NUMBER(12), ...

  6. PLSQL developer连接不上64位Oracle的解决方法

    PLSQL developer连接不上64位Oracle的解决方法 64位下装Oracle 11g 64位,PLSQL Developer使用出现问题. 问题描述: 登录对话框中,数据库下拉框为空: ...

  7. JAVA_SE基础——18.方法的递归

    方法的递归是指在一个方法的内部调用自身的过程,递归必须要有结束条件,不然就会陷入无限递归的状态,永远无法结束调用,接下来用一个最简单的例子来体现下方法递归,使用递归算法计算自然数之和: public ...

  8. [C#.Net]C#连接Oracle数据库的方法

    首先介绍下开发环境:WIn10 64bit+Visual Studio 2015+Oracle10ClientWin32(只是客户端,如果安装整个数据库也是可以的) 目前了解C#中连接Oracle数据 ...

  9. windows 7 下安装Oracle 9i 解决方法[转]

    这里首先申明下,windows7下安装oracle9i 9.0.1版本肯定是不成功的,楼主安装过无数次,网上也找过很多方法,都不可行,所以就不用试了.这里说下oracle9i 9.2版本安装出现的问题 ...

随机推荐

  1. JS的Event各种属性级target/currentTarget/relatedTarget各种目录的解释

    1.Event属性解释:https://developer.mozilla.org/zh-CN/docs/Web/API/Event 2.Event.target/currentTarget/rela ...

  2. 什么是 NetflixFeign?它的优点是什么?

    Feign 是受到 Retrofit,JAXRS-2.0 和 WebSocket 启发的 java 客户端联编程序.Feign 的第一个目标是将约束分母的复杂性统一到 http apis,而不考虑其稳定 ...

  3. Could not find the main class

    最近开发了一个短信报警的服务,打成程序包之后,再本地windows启动(start.bat)没有问题,但是发到生产环境,报如下错: Could not find the main class 莫名其妙 ...

  4. JPA、JTA、XA相关索引

    JPA和分布式事务简介:https://www.cnblogs.com/onlywujun/p/4784233.html JPA.JTA与JMS区别:https://www.cnblogs.com/y ...

  5. Iterator 和 ListIterator 有什么区别?

    1.ListIterator 可以在遍历的时候,调用add()添加元素 2.ListIterator提供了更多的一些方法,如previous().hasPrevious() 等

  6. mian中的argv调用时为什么不是*argv

    c++main函数char * argv[]是个指针数组,元素是指针,为何argv[1]得到不是地址? 照我的理解char *argv[]保存的应该是一组指针,即地址,每个地址中保存的是char类型变 ...

  7. 结合CSS3的布局新特征谈谈常见布局方法

    写在前面最近看到<图解CSS3>的布局部分,结合自己以前阅读过的一些布局方面的知识,这里进行一次基于CSS2.3的各种布局的方法总结. 常见的页面布局 在拿到设计稿时,作为一个前端人员,我 ...

  8. HTML5离线存储整理

    前端html部分 //canvas.html <!DOCTYPE html> <html manifest="/test.appcache"> <he ...

  9. 快如闪电,触控优先。新一代的纯前端控件集 WijmoJS发布新版本了

    全球最大的控件提供商葡萄城宣布,新一代纯前端控件 WijmoJS 发布2018 v1 版本,进一步增强产品功能,并支持在 Npm 上的安装和发布,极大的提升了产品的易用性. WijmoJS 是用 Ty ...

  10. WPF控件大全(表格)-学习总结

    Label标签 label控件:一般用户描述性文字显示. 在Label控件使用时,一般给予用户提示.用法上没有什么很特殊的,label控件的值记住:不是Text 而是 Content属性. TextB ...