Oracle with使用方法以及递归
数据准备
表结构
-- 部门表
CREATE TABLE DEPT (
dept_no VARCHAR2(5) NOT NULL,
dept_name VARCHAR2(255) NOT NULL,
PRIMARY KEY(dept_no)
);
-- 添加注释
COMMENT ON TABLE DEPT IS '部门表';
COMMENT ON COLUMN DEPT.dept_no IS '部门编码';
COMMENT ON COLUMN DEPT.dept_name IS '部门名称';
-- 员工表
CREATE TABLE EMP (
emp_no VARCHAR2(8) NOT NULL,
emp_name VARCHAR2(20) NOT NULL,
dept_no VARCHAR2(5) NOT NULL,
salary NUMBER(10, 2),
PRIMARY KEY(emp_no)
);
-- 添加注释
COMMENT ON TABLE EMP IS '员工表';
COMMENT ON COLUMN EMP.emp_no IS '员工编码';
COMMENT ON COLUMN EMP.emp_name IS '员工名称';
COMMENT ON COLUMN EMP.dept_no IS '所属部门编码';
COMMENT ON COLUMN EMP.salary IS '工资';
演示数据
-- 插入部门
insert into DEPT(dept_no, dept_name) values ('D001', '总经理部');
insert into DEPT(dept_no, dept_name) values ('D002', '人力资源部');
insert into DEPT(dept_no, dept_name) values ('D003', '行政后勤部');
insert into DEPT(dept_no, dept_name) values ('D004', '销售一部');
insert into DEPT(dept_no, dept_name) values ('D005', '销售二部');
insert into DEPT(dept_no, dept_name) values ('D006', '研发一部');
insert into DEPT(dept_no, dept_name) values ('D007', '研发二部');
-- 批量插入员工数据
declare
type e_name is varray(7) of varchar2(20);
e_name_arr e_name :=e_name('陈天龙','李晓红','田萌','张三','李四', '王五', '赵六');
begin
for d in 1..7 loop
for i in 1..(d*3) Loop
insert into EMP(emp_no, emp_name, dept_no, salary) values (
'E' || d || replace(lpad(i,5),' ','0'),
e_name_arr(d) || i || '号',
'D' || replace(lpad(d,3),' ','0'),
trunc(dbms_random.value(3,80)) * 1000
);
end loop;
end loop;
end;
基本语法
简单的with语句:
WITH t AS
(SELECT * FROM EMP)
SELECT * FROM t;
在视图中使⽤WITH语句进⾏连接:
CREATE OR REPLACE VIEW V_EMP_DETAIL AS
WITH W_DEPT AS (
SELECT * FROM DEPT
),
W_EMP AS (
SELECT * FROM EMP
)
SELECT d.dept_name, e.*
FROM W_EMP e
LEFT JOIN W_DEPT d ON d.dept_no = e.dept_no;
总结:
使⽤WITH AS 语句可以为⼀个⼦查询语句块定义⼀个名称,在查询语句的其他地⽅引⽤这个⼦查询。
Oracle 数据库像对待内联视图或临时表⼀样对待 被引⽤的⼦查询名称,从⽽起到⼀定的优化作⽤
在同级select前有多个查询定义的时候,第1个⽤with,后⾯的不⽤with,并且⽤逗号隔开。
最后⼀个with ⼦句与下⾯的查询之间不能有逗号,只通过右括号分割,with ⼦句的查询必须⽤括号括起来
WITH语句的优点:
- SQL可读性增强。⽐如对于特定with⼦查询取个有意义的名字等。
- with⼦查询只执⾏⼀次,将结果存储在⽤户临时表空间中,可以引⽤多次,增强性能。
示例
1、查询出部门的总工资⼤于所有部门平均总工资的部门。
分析:做这个查询,⾸先必须计算出所有部门的总工资,然后计算出所有部门的平均总工资,再筛选出部门的总工资⼤于所有部门总工资平均工资的部门。
- 那么第1步 with 查询查出所有部门的总工资
- 第2步⽤with 从第1 步获得的结果表中查询出平均工资
- 最后利⽤这两次 的with 查询⽐较总工资⼤于平均工资的结果
WITH W_DEPT_TOTAL_SALARY AS -- 查询出部门的总⼯资
( SELECT d.dept_name, SUM(e.salary) total_salary
FROM DEPT d
JOIN EMP e ON e.dept_no = d.dept_no
GROUP BY d.dept_name
),
W_DEPT_AVG_SALARY AS -- 查询出部门的平均⼯资,在后⼀个WITH语句中可以引⽤前⼀个定义的WITH语句
(
SELECT SUM(total_salary) / COUNT(1) avg_salary
FROM W_DEPT_TOTAL_SALARY
)
SELECT *
FROM W_DEPT_TOTAL_SALARY dts
WHERE dts.total_salary > ( -- 进⾏⽐较
SELECT das.avg_salary
FROM W_DEPT_AVG_SALARY das
);
2. 统计数据并关联到每条员工数据
展⽰根据查询结果查询出的数据,并把根据查询出的结果进⾏统计,如最⼤⼯资,最⼩⼯资,平均⼯资,
进⾏级联,由于查询的统计数据的条数为1条,所以不会发⽣笛卡⼉积的错误,
WITH W_EMP AS -- 查询基础数据
(
SELECT emp_no, emp_name, dept_no, salary
FROM EMP
),
W_EMP_DATA AS -- 查询统计数据
(
SELECT MAX(salary) as max_salary,
MIN(salary) as min_salary,
SUM(salary) as total_salary
FROM W_EMP
)
SELECT *
FROM W_EMP, W_EMP_DATA -- 进⾏级联,由于查询的统计数据的条数为1条,所以不会发⽣笛卡⼉积的错误
3. 后⾯的with定义可以引⽤前⾯的结果集,但是with⼦查询不可嵌套定义。
下⾯的语句错误:因为不允许嵌套定义with语句
WITH W_EMP_2 AS
-- with中有嵌套with,不允许
(
WITH W_EMP AS
(
SELECT emp_name FROM EMP WHERE emp_no='E100001'
)
SELECT emp_name FROM W_EMP
)
SELECT * FROM W_EMP_2;
递归案例
实现从1到10的输出
with w_num(n) as (
select 1 as n from dual
union all
select n+1 from w_num where n<10
)
select n from w_num;
空瓶换啤酒最多能喝几瓶问题
/**
2元1瓶啤酒
4个瓶盖换1瓶啤酒
2个空瓶换1瓶啤酒
问:10元可以喝几瓶
*/
with w_drink_beer(beer, bottle, lid) AS
(
select 10/2 as beer, 10/2 as bottle, 10/2 as lid
from dual
union all
select
beer + trunc(bottle/2) + trunc(lid/4) as beer,
mod(bottle, 2) + trunc(bottle/2) + trunc(lid/4) as bottle,
mod(lid, 4) + trunc(bottle/2) + trunc(lid/4) as lid
from w_drink_beer
where trunc(bottle/2) != 0 or trunc(lid/4) != 0
)
select beer as '喝了几瓶啤酒', bottle as '剩下几个瓶子', lid as '剩下几个瓶盖'
from w_drink_beer;
递归-地铁线路换乘问题
示例表和脚本下载:https://github.com/dongxuyang1985/sql_in_action
-- Oracle
WITH transfer (start_station, stop_station, stops, path) AS (
SELECT station_name, next_station, 1, line_name||station_name||'->'||line_name||next_station
FROM bj_subway WHERE station_name = '王府井'
UNION ALL
SELECT p.start_station, e.next_station, stops + 1, p.path||'->'||e.line_name||e.next_station
FROM transfer p
JOIN bj_subway e
ON p.stop_station = e.station_name AND (INSTR(p.path, e.next_station) = 0)
)
SELECT * FROM transfer WHERE stop_station ='积水潭';
Oracle with使用方法以及递归的更多相关文章
- .NET 基础 一步步 一幕幕[面向对象之方法、方法的重载、方法的重写、方法的递归]
方法.方法的重载.方法的重写.方法的递归 方法: 将一堆代码进行重用的一种机制. 语法: [访问修饰符] 返回类型 <方法名>(参数列表){ 方法主体: } 返回值类型:如果不需要写返回值 ...
- oracle 表迁移方法 (二) 约束不失效
DB:11.2.0.3.0 在oracle 表迁移方法 (一)中,只是move了一张普通的表,如果表的字段带有主键约束呢 ? [oracle@db01 ~]$ sqlplus / as sysdba ...
- 【转】PLSQL developer 连接不上64位Oracle 的解决方法
PLSQL developer 连接不上64位Oracle 的解决方法 快乐无极 , 2012/06/13 10:10 , 开发文档 , 评论(6) , 阅读(140430) , Via 本站原创 大 ...
- .net远程连接oracle数据库不用安装oracle客户端的方法
.net远程连接oracle数据库不用安装oracle客户端的方法步骤: 1.添加Sytem.Data.OracleClient命名空间. 2.连接时需要ConnectionString字符串,出现在 ...
- oracle创建job方法
oracle创建job方法 alter system enable restricted session;--创建表create table G_TEST ( ID NUMBER(12), ...
- PLSQL developer连接不上64位Oracle的解决方法
PLSQL developer连接不上64位Oracle的解决方法 64位下装Oracle 11g 64位,PLSQL Developer使用出现问题. 问题描述: 登录对话框中,数据库下拉框为空: ...
- JAVA_SE基础——18.方法的递归
方法的递归是指在一个方法的内部调用自身的过程,递归必须要有结束条件,不然就会陷入无限递归的状态,永远无法结束调用,接下来用一个最简单的例子来体现下方法递归,使用递归算法计算自然数之和: public ...
- [C#.Net]C#连接Oracle数据库的方法
首先介绍下开发环境:WIn10 64bit+Visual Studio 2015+Oracle10ClientWin32(只是客户端,如果安装整个数据库也是可以的) 目前了解C#中连接Oracle数据 ...
- windows 7 下安装Oracle 9i 解决方法[转]
这里首先申明下,windows7下安装oracle9i 9.0.1版本肯定是不成功的,楼主安装过无数次,网上也找过很多方法,都不可行,所以就不用试了.这里说下oracle9i 9.2版本安装出现的问题 ...
随机推荐
- loj3161「NOI2019」I 君的探险(随机化,整体二分)
loj3161「NOI2019」I 君的探险(随机化,整体二分) loj Luogu 题解时间 对于 $ N \le 500 $ 的点,毫无疑问可以直接 $ O(n^2) $ 暴力询问解决. 考虑看起 ...
- 【技术干货】华为云FusionInsight MRS的自研超级调度器Superior Scheduler
Superior Scheduler是一个专门为Hadoop YARN分布式资源管理系统设计的调度引擎,是针对企业客户融合资源池,多租户的业务诉求而设计的高性能企业级调度器. Superior Sch ...
- SQL 语言包括哪几部分?每部分都有哪些操作关键字?
SQL 语言包括数据定义(DDL).数据操纵(DML),数据控制(DCL)和数据查询(DQL) 四个部分. 数据定义:Create Table,Alter Table,Drop Table, Crae ...
- java线程池源码分析
我们在关闭线程池的时候会使用shutdown()和shutdownNow(),那么问题来了: 这两个方法又什么区别呢? 他们背后的原理是什么呢? 线程池中线程超过了coresize后会怎么操作呢? 为 ...
- 你对 Spring Boot 有什么了解?
事实上,随着新功能的增加,弹簧变得越来越复杂.如果必须启动新的 spring 项 目,则必须添加构建路径或添加 maven 依赖项,配置应用程序服务器,添加 spring 配置.所以一切都必须从头开始 ...
- Python - Pycharm常用快捷键
1. 自动格式调整: pycharm有自动调整代码格式的快捷键,默认为Alt+Ctrl+L 2. 选中相同字符: 快捷键组合:Ctrl + Shift + Alt + J 3.批量缩进: 选择代码区域 ...
- C语言思维导图—自己整理的
- 在网页中预览excel表格文件
项目需求在前端页面中实现预览excel表格的功能,上网了解之后大致总结为一下几种方法. 1.office文档转换为pdf,再转swf,然后通过网页加载flash进行预览 2.通过 xlsx.js,js ...
- for 循环详解
学习目标: 掌握 for 循环的使用 学习内容: 1.for语法 for(初始化语句; boolean表达式; 循环后操作语句) { 循环体; } 流程图如下: 特点: 初始化语句:只在循环开始时执行 ...
- 理解Promise函数中的resolve和reject
看了promise的用法,一直不明白里面的resolve和reject的用法: 运行了这两段代码之后彻底理解了promise的用法: var p = new Promise(function (res ...