SQL-递归查询在Ora与Mssql
今天在工作中,有同事“请教”从 Sql Server 移植数据到 DM DB 的改写问题,本以为难度不大,结果发现 Sql Server 数据库的语法、架构上,与 Oracle / DM 数据库差异还是蛮大的,弄得没怎么用过 Sql Server 的我十分头大,赶紧记载一些工作中遇到的问题,也加固 SQL 的学习,像递归查询这个问题,对我来说一直都是一个比较生涩的点。
在 Mssql 中,递归的语法是用 With 来实现的,所以一开始我还以为是要用 With 生成临时结果来处理,后来在网上查找了一下资料,才知道语法就是这样的。可以参考 TurboWay 博客(https://www.cnblogs.com/TurboWay/p/7728746.html)中的说法,于是我在笔记本上装了一个 Sql Server 2017 进行测试,为了方便,就采用了博客中的脚本进行测试。
/*
test表
ID 地区ID
Name 地区名称
Main_ID 地区所属上级ID
Sign 地区等级 例如:福建-厦门-湖里 分别是 1,2,3
*/
-- 建表
SELECT 1003 ID, '福建' Name, 0 Main_ID, 1 Sign INTO test union all
SELECT 1050 , '福州' , 1003 , 2 union all
SELECT 1051 , '厦门' , 1003 , 2 union ALL
SELECT 1375 , '思明' , 1051 , 3 union all
SELECT 1382 , '海沧' , 1051 , 3 union all
SELECT 1381 , '湖里' , 1051 , 3 union all
SELECT 1374 , '集美' , 1051 , 3 union all
SELECT 1373 , '同安' , 1051 , 3 union all
SELECT 1380 , '翔安' , 1051 , 3 union ALL
SELECT 667582720122 , '鼓楼' , 1050 , 3 union all
SELECT 667582725528 , '台江' , 1050 , 3 union all
SELECT 667582729587 , '仓山' , 1050 , 3 union all
SELECT 667582732602 , '马尾' , 1050 , 3 union all
SELECT 667582735385 , '晋安' , 1050 , 3 union all
SELECT 667582738507 , '闽侯' , 1050 , 3 union all
SELECT 667582742586 , '连江' , 1050 , 3 union all
SELECT 667582745634 , '罗源' , 1050 , 3 union all
SELECT 667582748358 , '闽清' , 1050 , 3 union all
SELECT 667582751824 , '永泰' , 1050 , 3 union all
SELECT 667582755215 , '平潭' , 1050 , 3 union all
SELECT 667582760309 , '福清' , 1050 , 3 union all
SELECT 667582764565 , '长乐' , 1050 , 3;
这里才发现,在 Mssql 中,可以通过这样创建表,有点类似 Oracle 语法中的 Create Table as Select 的方式。通过导出 DDL 可以看到表 test 中列的精度。
CREATE TABLE [dbo].[test](
[ID] [numeric](12, 0) NOT NULL,
[Name] [varchar](4) NOT NULL,
[Main_ID] [int] NOT NULL,
[Sign] [int] NOT NULL
) ON [PRIMARY]
GO
发现 number 类型和 varchar 类型,都是刚好是 id 列和 name 列的最大精度。表环境拟好以后,可以执行 SQL。
WITH CTE AS
(
--父项
SELECT a.*,1 level
FROM test a WHERE ID=1003
UNION ALL
--递归结果集中的下级
SELECT a.* , level + 1 as level
FROM test a
INNER JOIN CTE b ON b.ID=a.Main_ID
)select * from CTE; --结果集
ID Name Main_ID Sign level
--------------------------------------- ---- ----------- ----------- -----------
1003 福建 0 1 1
1050 福州 1003 2 2
1051 厦门 1003 2 2
1375 思明 1051 3 3
1382 海沧 1051 3 3
1381 湖里 1051 3 3
1374 集美 1051 3 3
1373 同安 1051 3 3
1380 翔安 1051 3 3
667582720122 鼓楼 1050 3 3
667582725528 台江 1050 3 3
667582729587 仓山 1050 3 3
667582732602 马尾 1050 3 3
667582735385 晋安 1050 3 3
667582738507 闽侯 1050 3 3
667582742586 连江 1050 3 3
667582745634 罗源 1050 3 3
667582748358 闽清 1050 3 3
667582751824 永泰 1050 3 3
667582755215 平潭 1050 3 3
667582760309 福清 1050 3 3
667582764565 长乐 1050 3 3
其实,从这个结果集就很好理解递归查询应用场景,以地点这个场景来解释层次查询是非常适合的,如果表中没有 Sign 这个列,在 Sql 中的 level 也能非常好的分层。第一层就是福建,福建下面的第二层地点就是福州和厦门, Sign = 3 的就是第三层地名。把它们关联起来的是Id 与 Main_id ,一般我们把 Main_id 叫 Parent id ,即它的父节点 id 。比如地点马尾,它的 Main_id 是1050,而 id 是1050的就是马尾的父节点——福州。如果我们把整个结果集当成一棵树的结构的话,在以上 Sql 中,是从 id = 1003 开始,遍历整棵树,Sign = 1 是根的话,Sign = 3 的就是这棵树的叶,这样的查询就是自顶向下(树形结构是倒着的)的一种层次查询。(仅个人理解,可能不准确)
而下面这样,就是自底向上的查询了,通过一个叶子节点去查找父节点。也很好理解,第一部分先获取到叶子节点的 id,第二部分,通过已经查到的叶子节点数据(cte as b)的父节点,来找父节点的数据(b.Main_id = test.id)。
with cte as (
select a.*,1 as level from test a where id = 667582751824
union all
select a.*,level + 1 as level from test a inner join cte as b
on a.id = b.Main_ID
) select * from cte; --结果集
ID Name Main_ID Sign level
--------------------------------------- ---- ----------- ----------- -----------
667582751824 永泰 1050 3 1
1050 福州 1003 2 2
1003 福建 0 1 3
在 Oracle 语法中,层次查询的语法与 Mssql 中不一样,以前在用到的时候,一直难以理解是怎么个关联关系的,直到在一个博客中看到一种说法:prior 就是"找"的意思,prior id 就是找叶子节点,自顶而下查询;prior parent_id 就是找父节点,即自底向上查询。这样解释起来就非常有意思而且便于记忆,是个非常棒的点。以下是 Oracle / DM 对应的SQL。
select * from test start with id=1003 connect by prior id= main_id;
select a.*,level from test a start with id = 667582735385 connect by prior main_id = id;
SQL-递归查询在Ora与Mssql的更多相关文章
- SQL递归查询实现跟帖盖楼效果
网易新闻的盖楼乐趣多,某一天也想实现诸如网易新闻跟帖盖楼的功能,无奈技术不佳(基础不牢),网上搜索了资料才发现SQL查询方法有一种叫递归查询,整理如下: 一.查询出 id = 1 的所有子结点 wit ...
- 【转】sql递归查询问题
原文链接地址http://www.cnblogs.com/sweting/archive/2009/06/08/1498483.html 在工作中遇到一个问题,是需要sql递归查询的.不懂,于是到cs ...
- SQL递归查询(with as)
SQL递归查询(with cte as) with cte as( select Id,Pid,DeptName,0 as lvl from Department where Id = 2 ...
- 关于SQL递归查询在不同数据库中的实现方法
比如表结构数据如下: Table:Tree ID Name ParentId 1 一级 0 2 二级 1 3 三级 2 4 四级 3 SQL SERVER 2005查询方法: //上查 with ...
- SQL递归查询知多少
最近工作中遇到了一个问题,需要根据保存的流程数据,构建流程图.数据库中保持的流程数据是树形结构的,表结构及数据如下图: 仔细观察表结构,会发现其树形结构的特点: FFIRSTNODE:标记是否为根节点 ...
- sql递归查询语句
sql Bom 递归查询: with t as(select * from Department where id=6union allselect a.* from Department a,t w ...
- PLSQL Developer概念学习系列之登录连接Oracle时出现(没有登录) -PL / SQL Developer:ORA - 12541: TNS :无建听程序的错误解决办法(图文详解)
不多说,直接上干货! 前期博客 PLSQL Developer概念学习系列之如何正确登录连接上Oracle(图文详解) 如用scott.scott_password进行登录,orcl是全局数据库 ...
- SQL监控:mysql及mssql数据库SQL执行过程监控审计
转载 Seay_法师 最近生活有很大的一个变动,所以博客也搁置了很长一段时间没写,好像写博客已经成了习惯,搁置一段时间就有那么点危机感,心里总觉得不自在.所以从今天起还是要继续拾起墨笔(键盘),继续好 ...
- SQL递归查询实现组织机构树
系统用到的组织机构树,要实现对当前节点以及其子节点的查询,数据库SQL要用到递归查询,这也是我第一次接触SQL的递归查询. 先说一下什么是递归查询,简单说来是将一个树状结构存储在一张表里,比如一个表中 ...
随机推荐
- linux ---docker篇
Docker docker是什么? docker最初是dotCloud公司创始人Solomom Hykes在法国期间发起的一个公司内部项目,它是基于dotCloud公司多年云服务技术的一次革新,并在2 ...
- MYSQL定时任务 触发器
流程: 查看时间调度器是否开启,OFF关闭,ON开启 SHOW VARIABLES LIKE 'event_scheduler' 设置开启 set GLOBAL event_scheduler = 1 ...
- 2018-2019-2 网络对抗技术 20165317 Exp4 恶意代码分析
2018-2019-2 网络对抗技术 20165317 Exp4 恶意代码分析 实验要求 1.系统运行监控 使用如计划任务,每隔一分钟记录自己的电脑有哪些程序在联网,连接的外部IP是哪里.运行一段时间 ...
- SecureCRT连接linux步骤
SecureCRT连接linux步骤 做个笔记,以免隔段时间后忘了 LINUX系统一般都是用来作服务器使用,而且都是通过命令行来操作,为了操作方便我们都会使用第三方软件来远程操作.CRT就是比较常用 ...
- MongoDB - Indexes
#explain command pp db[:zips].find(:state => 'MD').explain #List all indexes: db[:zips].indexes.e ...
- 解决fastDFS客户端连接超时问题
1.修改storage.conf配置tracker_server的ip为外网ip 2.开放23000端口
- iTerm2 与 Oh My Zsh的配套使用
详见: https://www.jianshu.com/p/7de00c73a2bb https://github.com/sirius1024/iterm2-with-oh-my-zsh https ...
- #学号 20175201张驰 《Java程序设计》第2周学习总结
教材学习内容总结: 一.第二章: 1:标识符与关键字 2:基本数据类型:四种整数类型(byte.short.int.long).两种浮点数类型(float.double).一种字符类型(char).一 ...
- 【Linux】-NO.160.Linux.1 -【升级Centos7】
Style:Mac Series:Java Since:2018-09-10 End:2018-09-10 Total Hours:1 Degree Of Diffculty:5 Degree Of ...
- leetcode143. Reorder List
用快慢双指针,可以使慢指针到达中间的时候快指针到达最后一个元素(奇数),或者倒数第二个元素(偶数).慢指针后面的元素是后半个链表,把后半个链表进行reverse,然后再插在原来的链表中就可以了 /** ...