通过START WITH . . . CONNECT BY . . .子句来实现SQL的层次查询.
自从Oracle 9i开始,可以通过 SYS_CONNECT_BY_PATH 函数实现将父节点到当前行内容以“path”或者层次元素列表的形式显示出来。

自从Oracle 10g 中,还有其他更多关于层次查询的新特性 。例如,有的时候用户更关心的是每个层次分支中等级最低的内容。
那么你就可以利用伪列函数CONNECT_BY_ISLEAF来判断当前行是不是叶子。如果是叶子就会在伪列中显示“1”,
如果不是叶子而是一个分支(例如当前内容是其他行的父亲)就显示“0”。

在Oracle 10g 之前的版本中,如果在你的树中出现了环状循环(如一个孩子节点引用一个父亲节点),
Oracle 就会报出一个错误提示:“ ORA-01436: CONNECT BY loop in user data”。如果不删掉对父亲的引用就无法执行查询操作。
而在 Oracle 10g 中,只要指定“NOCYCLE”就可以进行任意的查询操作。与这个关键字相关的还有一个伪列——CONNECT_BY_ISCYCLE,
如果在当前行中引用了某个父亲节点的内容并在树中出现了循环,那么该行的伪列中就会显示“1”,否则就显示“0”。

The start with .. connect by clause can be used to select data that has a hierarchical relationship
(usually some sort of parent->child, boss->employee or thing->parts).
It is also being used when an sql execution plan is explained.

syntax:
select ... [start with initial-condition] connect by [nocycle] recurse-condition

level
With level it is possible to show the level in the hierarchical relation of all the data.

--oracle 9i
sys_connect_by_path
With sys_connect_by_path it is possible to show the entire path from the top level down to the 'actual' child.

--oracle 10g
connect_by_root
connect_by_root is a new operator that comes with Oracle 10g and enhances the ability to perform hierarchical queries.
connect_by_is_leaf
connect_by_isleaf is a new operator that comes with Oracle 10g and enhances the ability to perform hierarchical queries.
connect_by_iscycle
connect_by_is_cycle is a new operator that comes with Oracle 10g and enhances the ability to perform hierarchical queries.

--start with ... connect by ... 的处理机制
How must a start with ... connect by select statement be read and interpreted?
If Oracle encounters such an SQL statement, it proceeds as described in the following pseude code.

for rec in (select * from some_table) loop
if FULLFILLS_START_WITH_CONDITION(rec) then
RECURSE(rec, rec.child);
end if;
end loop;

procedure RECURSE (rec in MATCHES_SELECT_STMT, new_parent IN field_type) is
begin
APPEND_RESULT_LIST(rec);
for rec_recurse in (select * from some_table) loop
if FULLFILLS_CONNECT_BY_CONDITION(rec_recurse.child, new_parent) then
RECURSE(rec_recurse,rec_recurse.child);
end if;
end loop;
end procedure RECURSE;

created by zhouwf0726 2006.

*******************************************************************************/

--创建测试表,增加测试数据

Sql代码
  1. create table test(superid varchar2(20),id varchar2(20));
  2. insert into test values('0','1');
  3. insert into test values('0','2');
  4. insert into test values('1','11');
  5. insert into test values('1','12');
  6. insert into test values('2','21');
  7. insert into test values('2','22');
  8. insert into test values('11','111');
  9. insert into test values('11','112');
  10. insert into test values('12','121');
  11. insert into test values('12','122');
  12. insert into test values('21','211');
  13. insert into test values('21','212');
  14. insert into test values('22','221');
  15. insert into test values('22','222');
  16. commit;
  17. --层次查询示例
  18. select level||'层',lpad(' ',level*5)||id id
  19. from test
  20. start with superid = '0' connect by prior id=superid;
  21. select level||'层',connect_by_isleaf,lpad(' ',level*5)||id id
  22. from test
  23. start with superid = '0' connect by prior id=superid;
  24. --给出两个以前在"数据库字符串分组相加之四"中的例子来理解start with ... connect by ...
  25. --功能:实现按照superid分组,把id用";"连接起来
  26. --实现:以下两个例子都是通过构造2个伪列来实现connect by连接的。
  27. /*------method one------*/
  28. select superid,ltrim(max(sys_connect_by_path(id,';')),';') from(
  29. select superid,id,row_number() over(partition by superid order by superid) id1,
  30. row_number() over(order by superid) + dense_rank() over(order by superid) id2
  31. from test
  32. )
  33. start with id1=1 connect by prior id2 = id2 -1
  34. group by superid order by superid;
  35. /*------method two------*/
  36. select distinct superid,ltrim(first_value(id) over(partition by superid order by l desc),';')
  37. from(
  38. select superid,level l,sys_connect_by_path(id,';') id
  39. from(
  40. select superid,id,superid||rownum parent_rn,superid||to_char(rownum-1) rn
  41. from test
  42. )
  43. connect by prior parent_rn = rn
  44. );
  45. --下面的例子实现把一个整数的各个位上的数字相加,通过这个例子我们再次理解connect by.
  46. create or replace function f_digit_add(innum integerreturn number
  47. is
  48. outnum integer;
  49. begin
  50. if innum<0 then
  51. return 0;
  52. end if;
  53. select sum(nm) into outnum from(
  54. select substr(innum,rownum,1) nm from dual connect by rownum<length(innum)
  55. );
  56. return outnum;
  57. end f_digit_add;
  58. /
  59. select f_digit_add(123456) from dual;
create table test(superid varchar2(20),id varchar2(20));insert into test values('0','1');
insert into test values('0','2');insert into test values('1','11');
insert into test values('1','12');insert into test values('2','21');
insert into test values('2','22');insert into test values('11','111');
insert into test values('11','112');insert into test values('12','121');
insert into test values('12','122');insert into test values('21','211');
insert into test values('21','212');insert into test values('22','221');
insert into test values('22','222');commit;--层次查询示例
select level||'层',lpad(' ',level*5)||id id
from test
start with superid = '0' connect by prior id=superid;select level||'层',connect_by_isleaf,lpad(' ',level*5)||id id
from test
start with superid = '0' connect by prior id=superid;--给出两个以前在"数据库字符串分组相加之四"中的例子来理解start with ... connect by ...
--功能:实现按照superid分组,把id用";"连接起来
--实现:以下两个例子都是通过构造2个伪列来实现connect by连接的。/*------method one------*/
select superid,ltrim(max(sys_connect_by_path(id,';')),';') from(
select superid,id,row_number() over(partition by superid order by superid) id1,
row_number() over(order by superid) + dense_rank() over(order by superid) id2
from test
)
start with id1=1 connect by prior id2 = id2 -1
group by superid order by superid;/*------method two------*/
select distinct superid,ltrim(first_value(id) over(partition by superid order by l desc),';')
from(
select superid,level l,sys_connect_by_path(id,';') id
from(
select superid,id,superid||rownum parent_rn,superid||to_char(rownum-1) rn
from test
)
connect by prior parent_rn = rn
);--下面的例子实现把一个整数的各个位上的数字相加,通过这个例子我们再次理解connect by.create or replace function f_digit_add(innum integer) return number
is
outnum integer;
begin
if innum<0 then
return 0;
end if;
select sum(nm) into outnum from(
select substr(innum,rownum,1) nm from dual connect by rownum<length(innum)
);
return outnum;
end f_digit_add;
/select f_digit_add(123456) from dual;

/**********************************************************************************
***********************************************************************************
下面是关于SQL解决有向图问题,在这个例子中作者提到的错误
select * from fares connect by prior arrive = depart start with depart = 'LHR';
ERROR:
ORA-01436: CONNECT BY loop in user data
在oracle10g以上版本可以利用connect by的nocycle参数来解。有兴趣的朋友研究用一条sql实现有向图问题!
***********************************************************************************
**********************************************************************************/

一个常见的高级计算机科学问题可以在“有向图”的范畴之下描述。有向图是由一组向量和边所连接的一组有限的节点。
例如,一个节点可以想象为一座“城市”,而每个向量可以想象为两座城市间的一个“航线”。
有很多算法和论文讲到如何解决每种可能路线的遍历问题以及寻找最短路径或者最小代价路径的问题。
这些算法中大部分都是过程化的,或者是使用递归方面来解决的。然而 SQL 的声明性语言使得解决复杂的有向图问题更加容易,
而且不需要很多代码。

让我们以两座城市之间的航线为例子,创建一个表保存一些假想数据:

Sql代码
  1. create table airports
  2. (
  3. code char(3) constraint airports_pk primary key,
  4. description varchar2(200)
  5. );
  6. insert into airports values ('LHR','London Heathrow, UK');
  7. insert into airports values ('JFK','New York-Kennedy, USA');
  8. insert into airports values ('GRU','Sao Paulo, Brazil');
  9. create table fares
  10. (
  11. depart char(3),
  12. arrive char(3),
  13. price number,
  14. constraint fares_pk primary key (depart,arrive),
  15. constraint fares_depart_fk foreign key (depart) references airports,
  16. constraint fares_arrive_fk foreign key (arrive) references airports
  17. );
  18. insert into fares values('LHR','JFK',700);
  19. insert into fares values('JFK','GRU',600);
  20. insert into fares values('LHR','GRU',1500);
  21. insert into fares values('GRU','LHR',1600);
create table airports
(
code char(3) constraint airports_pk primary key,
description varchar2(200)
);insert into airports values ('LHR','London Heathrow, UK');
insert into airports values ('JFK','New York-Kennedy, USA');
insert into airports values ('GRU','Sao Paulo, Brazil');create table fares
(
depart char(3),
arrive char(3),
price number,
constraint fares_pk primary key (depart,arrive),
constraint fares_depart_fk foreign key (depart) references airports,
constraint fares_arrive_fk foreign key (arrive) references airports
);insert into fares values('LHR','JFK',700);
insert into fares values('JFK','GRU',600);
insert into fares values('LHR','GRU',1500);
insert into fares values('GRU','LHR',1600);

不能使用CONNECT BY 语法来解决如何从伦敦到圣保罗,因为在图中有数据产生一个环(从圣保罗飞回):

Sql代码
  1. select * from fares connect by prior arrive = depart start with depart = 'LHR';
select * from fares connect by prior arrive = depart start with depart = 'LHR';

ERROR:
ORA-01436: CONNECT BY loop in user data

要解决有向图问题,我们需要创建一个临时表来保存两个节点之间所有可能的路径。我们必须注意不复制已经处理过的路径,
而且在这种情况下,我们不想路径走回开始处的同一个地点。我还希望跟踪到达目的地所需航程的数目,以及所走路线的描述。

临时表使用以下脚本创建:

Sql代码
  1. create global temporary table faretemp
  2. (
  3. depart char(3),
  4. arrive char(3),
  5. hops integer,
  6. route varchar2(30),
  7. price number,
  8. constraint faretemp_pk primary key (depart,arrive)
  9. );
create global temporary table faretemp
(
depart char(3),
arrive char(3),
hops integer,
route varchar2(30),
price number,
constraint faretemp_pk primary key (depart,arrive)
);

一个简单的视图可以在稍微简化这个例子中使用的代码。视图可以根据 fares 表中的单个航程计算从 faretemp 表中的一个路径
到达一下一个航程的数据:

Sql代码
  1. create or replace view nexthop
  2. as
  3. select src.depart,
  4. dst.arrive,
  5. src.hops+1 hops,
  6. src.route||','||dst.arrive route,
  7. src.price + dst.price price
  8. from faretemp src,fares dst
  9. where src.arrive = dst.depart
  10. and dst.arrive != src.depart;
  11. /
  12. show errors;
create or replace view nexthop
as
select src.depart,
dst.arrive,
src.hops+1 hops,
src.route||','||dst.arrive route,
src.price + dst.price price
from faretemp src,fares dst
where src.arrive = dst.depart
and dst.arrive != src.depart;
/
show errors;

这个算法相当简单。首先,使用 fares 表中的数据填充 faretemp 表,作为初始的航程。然后,取到我们刚才插入的所有数据,
使用它们建立所有可能的二航程(two-hop)路径。重复这一过程,直至在两个节点之间创建了新路径。
循环过程将在节点间所有可能的路径都被描述之后退出。如果我们只对某个开始条件感兴趣,
那么我们还可以限制第一次的插入从而减少装载数据的量。下面是发现路径的代码:

Sql代码
  1. truncate table faretemp;
  2. begin
  3. -- initial connections
  4. insert into faretemp
  5. select depart,arrive,1,depart||','||arrive,price from fares;
  6. while sql%rowcount > 0 loop
  7. insert into faretemp
  8. select depart,arrive,hops,route,price from nexthop
  9. where (depart,arrive)
  10. not in (select depart,arrive from faretemp);
  11. end loop;
  12. end;
  13. /
  14. show errors;
  15. select * from faretemp order by depart,arrive;
truncate table faretemp;
begin
-- initial connections
insert into faretemp
select depart,arrive,1,depart||','||arrive,price from fares;
while sql%rowcount > 0 loop
insert into faretemp
select depart,arrive,hops,route,price from nexthop
where (depart,arrive)
not in (select depart,arrive from faretemp);
end loop;
end;
/
show errors;select * from faretemp order by depart,arrive;

可以在表 A 中查看输出。

前面的数据有一个小问题。数据是点之间最短路径(最小航程数)的集合。然而,从伦敦到圣保罗的航程却不是最便宜的一个。

要解决最便宜的费用问题,需要对我们的循环做一个改进,当在一个航程中发现一个更便宜的路线时使用这个路线代替原来的路线。
修改后的代码如下:

Sql代码
  1. truncate table faretemp;
  2. declare
  3. l_count integer;
  4. begin
  5. -- initial connections
  6. insert into faretemp
  7. select depart,arrive,1,depart||','||arrive,price from fares;
  8. l_count := sql%rowcount;
  9. while l_count > 0 loop
  10. update faretemp
  11. set (hops,route,price) =
  12. (select hops,route,price from nexthop
  13. where depart = faretemp.depart
  14. and arrive = faretemp.arrive)
  15. where (depart,arrive) in
  16. (select depart,arrive from nexthop
  17. where price < faretemp.price);
  18. l_count := sql%rowcount;
  19. insert into faretemp
  20. select depart,arrive,hops,route,price from nexthop
  21. where (depart,arrive)
  22. not in (select depart,arrive from faretemp);
  23. l_count := l_count + sql%rowcount;
  24. end loop;
  25. end;
  26. /
  27. show errors;
  28. select * from faretemp order by depart,arrive;
truncate table faretemp;
declare
l_count integer;
begin
-- initial connections
insert into faretemp
select depart,arrive,1,depart||','||arrive,price from fares;
l_count := sql%rowcount;
while l_count > 0 loop
update faretemp
set (hops,route,price) =
(select hops,route,price from nexthop
where depart = faretemp.depart
and arrive = faretemp.arrive)
where (depart,arrive) in
(select depart,arrive from nexthop
where price < faretemp.price);
l_count := sql%rowcount;
insert into faretemp
select depart,arrive,hops,route,price from nexthop
where (depart,arrive)
not in (select depart,arrive from faretemp);
l_count := l_count + sql%rowcount;
end loop;
end;
/
show errors;select * from faretemp order by depart,arrive;

可能在表 B中查看输出。

算法发现LHR、JFK、GRU 路线比 LHR、GRU 路线便宜,所以用前者代替了后者。循环将在没有更便宜的费用,
并且没有其它可能路线时退出。

concent by start with相关推荐

  1. react 哲学_细聊Concent amp; Recoil , 探索react数据流的新开发模式

    开源不易,感谢你的支持,❤ star me if you like concent ^_^ 序言 之前发表了一篇文章 redux.mobx.concent特性大比拼, 看后生如何对局前辈,吸引了不少感 ...

  2. 聊一聊状态管理Concent设计理念

    状态管理是一个前端界老生常谈的话题了,所有前端框架的发展历程中都离不开状态管理的迭代与更替,对于react来说呢,整个状态管理的发展也随着react架构的变更和新特性的加入而不停的做调整,作为一个一起 ...

  3. 【Web技术】624- redux、mobx、concent 状态管理方案对比

    授权原创:幻魂,来自掘金.如需查看文中 Demo,点击阅读原文. 序言 redux.mobx本身是一个独立的状态管理框架,各自有自己的抽象api,以其他UI框架无关(react, vue...),本文 ...

  4. 助力ssr,使用concent为nextjs应用加点料

    开源不易,感谢你的支持,❤ star concent_ 序言 nextjs是一个非常流行的 React 服务端渲染应用框架,它很轻量,简单易上手,社区活跃,所以当我们使用react写一个需要ssr(s ...

  5. python基础知识填空-Python基础知识练习题(一)

    1.执行Python脚本的两种方式:WIN+R,cmd,命令行窗口输入:python 进入python模式输入命令行直接执行命令:编写以.py结尾的文件,写入命令行,然后运行python.exe打开后 ...

  6. python 下载网页文件_『如何用python把网页上的文本内容保存下来』python爬取网页内容教程...

    python爬虫:如何爬网页数据并将其放在文本 用requests库 r=r.requests.get(url) r.concent 保存到文件里就行了 如何用python把网页上的文本内容保存下来 ...

  7. react生命周期函数_如何优雅的消灭掉react生命周期函数

    开源不易,感谢你的支持,❤ star concent^_^ 序言 在react应用里,存在一个顶层组件,该组件的生命周期很长,除了人为的调用unmountComponentAtNode接口来卸载掉它和 ...

  8. 【python之路14】发送邮件实例

    1.发邮件的代码 from email.mime.text import MIMETextfrom email.utils import formataddrimport smtplibmsg = M ...

  9. 论文 计算机网络安全现状的分析与对策,计算机网络安全现状的分析与对策(学年论文).pdf...

    计算机网络安全现状的分析与对策 摘 要:近年来我国计算机网络应用发展迅速,已经遍布经济.文化.科研.军事.教育和社 会生活等各个领域,由此网络安全问题成了新的热点.计算机网络安全问题,直接关系到一个国 ...

最新文章

  1. 亚马逊:我们提取了BERT的一个最优子架构,只有Bert-large的16%,CPU推理速度提升7倍...
  2. Windows 11 正式官宣:全新 UI、支持安卓 App、应用商店 0 抽成!
  3. Mysql 安全加固
  4. linux和java_java内存和linux关系
  5. 程序 峰谷值 提取_医学影像组学特征值(Radiomics Features)提取之Pyradiomics(一)理论篇...
  6. Faster R-CNN 英文论文翻译笔记
  7. 服务器u盘安装linux6.7,制作linux系统U盘并使用U盘安装CentOS7.6系统
  8. P5341-[TJOI2019]甲苯先生和大中锋的字符串【SAM】
  9. 未知的生成错误 因为没有预加载,所以无法解析程序集 GalaSoft.MvvmLight
  10. Docker logs 查看实时日志(日志最后的N行、某刻后日志)
  11. 《Python核心编程》第二版第18页第一章练习 -Python核心编程答案-自己做的-
  12. springboot thymeleaf模板使用
  13. arduino 智能车组装步骤_Arduino 自动避障智能小车制作教程
  14. 【高并发】秒杀系统设计思路
  15. 如何在matlab中设置colorbar
  16. matlab极坐标图刻度,[转载]如何在Matlab极坐标polar绘图上增加刻度单位
  17. 用C/C++手撕CPlus语言的集成开发环境(1)—— 语言规范 + 词法分析器
  18. java 视频边下边播,VideoViewDemo android 播放器,支持边下边播 238万源代码下载- www.pudn.com...
  19. 百度地图之添加覆盖物并响应事件
  20. 2022年PMP考试的3A好考吗?

热门文章

  1. 《Java逍遥游记》
  2. vc声音录制播放程序(附demo)
  3. 李宗盛唱《给自己的歌》现场失控泪奔:想得却不可得,你奈人生何?
  4. mysql 表名 下划线_忘掉数据库的下划线命名方式
  5. 2023年华中师范大学政治学专业考研参考书、难度及各科备考经验
  6. android画板控件,GitHub - imaiya/PainterView: Android画板控件,可以写字画画并生成图片...
  7. Actor-Critic(AC)算法学习
  8. nodejs运行环境配置并使用puppeteer实现后台截图
  9. 生物识别产业指纹识别锁在门禁锁的战略性前景
  10. 理解一维数组中buf\buf[0]\buf[0]\buf四个符号的含义