cubrid的中sql查询语法Hierarchical QuerySQL层级查询

------ 官方文档是英文的,看不明白可以参看ocracle的同类函数说明.很多都是一样的.

ORACLE中CONNECT BY...START WITH

和ocracle的差不多 ,下面的说明就直接抄袭过来

http://www.iwwenbo.com/oracle-start-with-connect-by/

其中,[where 条件1] 可以不需要,[where 条件1]是对根据[start with 条件2 connect by 条件3]选择出来的记录进行过滤,是针对单条记录的过滤,不会考虑树形查询的树结构;

[start with 条件2 ]限定作为搜索起始点的条件,表示从满足什么条件的记录开始查询;[connect by 条件3]表示查询的连接条件,树形菜单的查询常常是因为记录与记录之间存在某种关系,这种关系通常就作为连接条件。

补充:connect by子句,通常跟关键字“PRIOR”一起使用,“PRIOR”关键字的位置通常有两种,”CONNECT BY PRIOR ID = PID”和”CONNECT BY ID = PRIOR PID”,关键字位置的不同,相应的会导致查询结果的不同。

示例:

--创建表

create table tb_menu(

id number(10) not null,--主键ID

pid number(10) not null,--父菜单ID

title varchar2(50),--菜单名称

);

--添加数据

--父菜单

insert into tb_menu(id, pid,title ) values(1,父菜单1',0);

insert into tb_menu(id, pid,title ) values(2,父菜单2',0);

insert into tb_menu(id, pid,title ) values(3,父菜单3',0);

insert into tb_menu(id, pid,title ) values(4,父菜单4',0);

insert into tb_menu(id, pid,title ) values(5,父菜单5',0);

--一级菜单

insert into tb_menu(id, pid,title) values(6,1,'一级菜单6');

insert into tb_menu(id, pid,title) values(7,1,'一级菜单7');

insert into tb_menu(id, pid,title) values(8,1,'一级菜单8');

insert into tb_menu(id, pid,title) values(9,2,'一级菜单9');

insert into tb_menu(id, pid,title) values(10, 2, '一级菜单10');

insert into tb_menu(id, pid,title) values(11, 2, '一级菜单11');

insert into tb_menu(id, pid,title) values(12, 3,'一级菜单12');

insert into tb_menu(id, pid,title) values(13, 3,'一级菜单13');

insert into tb_menu(id, pid,title) values(14, 3,'一级菜单14');

insert into tb_menu(id, pid,title) values(15, 4,'一级菜单15');

insert into tb_menu(id, pid,title) values(16, 4,'一级菜单16');

insert into tb_menu(id, pid,title) values(17, 4,'一级菜单17');

insert into tb_menu(id, pid,title) values(18, 5,'一级菜单18');

insert into tb_menu(id, pid,title) values(19, 5,'一级菜单19');

insert into tb_menu(id, pid,title) values(20, 5,'一级菜单20');

--二级菜单

insert into tb_menu(id, title, pid) values(21, '二级菜单21',6);

insert into tb_menu(id, title, pid) values(22, '二级菜单22',6);

insert into tb_menu(id, title, pid) values(23, '二级菜单23',7);

insert into tb_menu(id, title, pid) values(24, '二级菜单24',7);

insert into tb_menu(id, title, pid) values(25, '二级菜单25',8);

insert into tb_menu(id, title, pid) values(26, '二级菜单26',9);

insert into tb_menu(id, title, pid) values(27, '二级菜单27',10);

insert into tb_menu(id, title, pid) values(28, '二级菜单28',11);

insert into tb_menu(id, title, pid) values(29, '二级菜单29',12);

insert into tb_menu(id, title, pid) values(30, '二级菜单30',13);

insert into tb_menu(id, title, pid) values(31, '二级菜单31',14);

insert into tb_menu(id, title, pid) values(32, '二级菜单32',15);

insert into tb_menu(id, title, pid) values(33, '二级菜单33',16);

insert into tb_menu(id, title, pid) values(34, '二级菜单34',17);

insert into tb_menu(id, title, pid) values(35, '二级菜单35',18);

insert into tb_menu(id, title, pid) values(36, '二级菜单36',19);

insert into tb_menu(id, title, pid) values(37, '二级菜单37',20);

--三级菜单

insert into tb_menu(id, title, pid) values(38, '三级菜单38',21);

insert into tb_menu(id, title, pid) values(39, '三级菜单39',22);

insert into tb_menu(id, title, pid) values(40, '三级菜单40',23);

insert into tb_menu(id, title, pid) values(41, '三级菜单41',24);

insert into tb_menu(id, title, pid) values(42, '三级菜单42',25);

insert into tb_menu(id, title, pid) values(43, '三级菜单43',26);

insert into tb_menu(id, title, pid) values(44, '三级菜单44',27);

insert into tb_menu(id, title, pid) values(45, '三级菜单45',28);

insert into tb_menu(id, title, pid) values(46, '三级菜单46',28);

insert into tb_menu(id, title, pid) values(47, '三级菜单47',29);

insert into tb_menu(id, title, pid) values(48, '三级菜单48',30);

insert into tb_menu(id, title, pid) values(49, '三级菜单49',31);

insert into tb_menu(id, title, pid) values(50, '三级菜单50',31);

commit;

说明:pid字段存储的是当前菜单节点的上级id,如果菜单节点是顶级节点,该菜单没有上级菜单,则pid应为null,然而在表中记录最好不要为null,建议使用0代替,因为null记录会引起全文扫描。

2.语法说明

oracle中递归查询(树形查询)主要依托于:

select * from table_name [where 条件1] start with 条件2 connect by 条件3;

其中,[where 条件1] 可以不需要,[where 条件1]是对根据[start with 条件2 connect by 条件3]选择出来的记录进行过滤,是针对单条记录的过滤,不会考虑树形查询的树结构;

[start with 条件2 ]限定作为搜索起始点的条件,表示从满足什么条件的记录开始查询;[connect by 条件3]表示查询的连接条件,树形菜单的查询常常是因为记录与记录之间存在某种关系,这种关系通常就作为连接条件。

补充:connect by子句,通常跟关键字“PRIOR”一起使用,“PRIOR”关键字的位置通常有两种,”CONNECT BY PRIOR ID = PID”和”CONNECT BY ID = PRIOR PID”,关键字位置的不同,相应的会导致查询结果的不同。

3.递归查询(树形查询)实践

只有上面的文字说明可能还是搞不清楚树形查询,不过动手来操作一遍就清楚了。

我们从最基本的操作,逐步列出常见的树查询操作,所有的查询以家族中的辈分作比方。

1)查询树中的所有顶级父节点(家族中辈分最大的那一代人)。假如这个树是个目录结构,那么第一个操作总是找出所有的顶级节点,然后再逐个根据顶级节点找到其子节点。

select * from tb_menu m where m.pid = 0;

以上查询得到的就是树的所有顶级节点,也就是家族中辈分最大的那一代人。

2)查找一个节点的直属子节点(家族中某个长辈的所有儿子),此时查找的是直属的子类节点,也是用不到树形查询的。

select * from tb_menu m where m.pid=1;

3)查找一个节点的所有直属子节点(家族中某个长辈的所有直系子孙)。

select * from tb_menu m start with m.id=1 connect by m.pid=prior m.id;

4)查找一个节点的直属父节点(家族中的父亲),此时查找的是节点的直属父节点,也是用不到树形查询的

select c.id, c.title, p.id parent_id, p.title parent_title

from tb_menu c, tb_menu p

where c.pid=p.id and c.id=6

5)查找一个节点的所有直属父节点(家族中一个孩子的所有直系长辈祖先,比如父亲,祖父,……)

select * from tb_menu m start with m.id=38 connect by prior m.pid=m.id;

说明:

上面的3)和5),这两条查询都是树形查询,区别在于”prior”关键字的位置不同,所以决定了查询方式的不同,查询结果也不同。当 pid = prior id时,数据库会根据当前的id迭代出pid与该id相同的记录,所以查询的结果是迭代出了所有的子类记录;而prior pid = id时,数据库会跟据当前的pid来迭代出与当前的pid相同的id的记录,所以查询出来的结果就是所有的父类结果。

仔细看一下数据库的查询结果,可以发现,其实3)和5)的查询顺序也是不同的,3)是自上向下检索,5)是自下向上检索。

以下是一系列针对树结构的更深层次的查询,这里的查询不一定是最优的查询方式,或许只是其中的一种实现而已。

6)查询一个节点的兄弟节点(亲兄弟)

--m.parent=m2.parent-->同一个父亲

select * from tb_menu m

where exists (select * from tb_menu m2 where m.pid=m2.pid and m2.id=6)

7)查询与一个节点同级的节点(族兄弟)。 如果在表中设置了级别的字段,那么在做这类查询时会很轻松,同一级别的就是与那个节点同级的,在这里列出不使用该字段时的实现!

with tmp as

(select a.*, level leaf

from tb_menu a

start with a.pid = 0

connect by a.pid = prior a.id)

select * from tmp where leaf = (select leaf from tmp where id = 50);

这里使用两个技巧,一个是使用了level来标识每个节点在表中的级别,还有就是使用with语法模拟出了一张带有级别的临时表。

8)查询一个节点的父节点的的兄弟节点(伯父与叔父)

with tmp as(

select tb_menu.*, level lev

from tb_menu

start with pid=0

connect by pid = prior id)

select b.*

from tmp b,(select *

from tmp

where id = 21 and lev = 2) a

where b.lev = 1

union all

select *

from tmp

where pid = (select distinct x.id

from tmp x, --祖父

tmp y, --父亲

(select *

from tmp

where id = 21 and lev > 2) z --儿子

where y.id = z.pid and x.id = y.pid);

这里查询分成以下几步。

首先,和第7个一样,将全表都使用临时表加上级别;

其次,根据级别来判断有几种类型,以上文中举的例子来说,有三种情况:

(1)当前节点为顶级节点,即查询出来的lev值为1,那么它没有上级节点,不予考虑。

(2)当前节点为2级节点,查询出来的lev值为2,那么就只要保证lev级别为1的就是其上级节点的兄弟节点。

(3)其它情况就是3以及以上级别,那么就要选查询出来其上级的上级节点(祖父),再来判断祖父的下级节点都是属于该节点的上级节点的兄弟节点。

最后,就是使用union将查询出来的结果进行结合起来,形成结果集。

**来看看官方的**

CREATE TABLE tree(ID INT, MgrID INT, Name VARCHAR(32), BirthYear INT);

INSERT INTO tree VALUES (1,NULL,'Kim', 1963);

INSERT INTO tree VALUES (2,NULL,'Moy', 1958);

INSERT INTO tree VALUES (3,1,'Jonas', 1976);

INSERT INTO tree VALUES (4,1,'Smith', 1974);

INSERT INTO tree VALUES (5,2,'Verma', 1973);

INSERT INTO tree VALUES (6,2,'Foster', 1972);

INSERT INTO tree VALUES (7,6,'Brown', 1981);

CREATE TABLE tree2(id int, treeid int, job varchar(32));

INSERT INTO tree2 VALUES(1,1,'Partner');

INSERT INTO tree2 VALUES(2,2,'Partner');

INSERT INTO tree2 VALUES(3,3,'Developer');

INSERT INTO tree2 VALUES(4,4,'Developer');

INSERT INTO tree2 VALUES(5,5,'Sales Exec.');

INSERT INTO tree2 VALUES(6,6,'Sales Exec.');

INSERT INTO tree2 VALUES(7,7,'Assistant');

INSERT INTO tree2 VALUES(8,null,'Secretary');

SELECT t.id,t.name,t2.job,level

FROM tree t INNER JOIN tree2 t2 ON t.id=t2.treeid

START WITH t.mgrid is null

CONNECT BY prior t.id=t.mgrid

ORDER BY t.id;

结果 能看到层次

id name job level

1  'Kim'                 'Partner'                       1
2 'Moy' 'Partner' 1
3 'Jonas' 'Developer' 2
4 'Smith' 'Developer' 2
5 'Verma' 'Sales Exec.' 2
6 'Foster' 'Sales Exec.' 2
7 'Brown' 'Assistant' 3 Ordering Data with the Hierarchical Query SELECT id, mgrid, name, birthyear, level

FROM tree

START WITH mgrid IS NULL

CONNECT BY PRIOR id=mgrid

ORDER SIBLINGS BY birthyear;

id mgrid name birthyear level

2         NULL  'Moy'                        1958            1
6 2 'Foster' 1972 2
7 6 'Brown' 1981 3
5 2 'Verma' 1973 2
1 NULL 'Kim' 1963 1
4 1 'Smith' 1974 2
3 1 'Jonas' 1976 2

SELECT id, mgrid, name, birthyear, level

FROM tree

START WITH mgrid IS NULL

CONNECT BY PRIOR id=mgrid

ORDER SIBLINGS BY birthyear;

level关键字

理解上面的,就理解下面的了

SELECT id, mgrid, name, LEVEL

FROM tree

WHERE LEVEL=2

START WITH mgrid IS NULL

CONNECT BY PRIOR id=mgrid

ORDER BY id;

还可以加条件

SELECT LEVEL FROM db_root CONNECT BY LEVEL <= 10;

CONNECT_BY_ISLEAF 关键字

connect_by_isleaf是叶节点1 不是0

SELECT id, mgrid, name, CONNECT_BY_ISLEAF

FROM tree

START WITH mgrid IS NULL

CONNECT BY PRIOR id=mgrid

ORDER BY id;

CONNECT_BY_ISCYCLE关键字

这个伪列功能是揪出那些“违反伦理道德”的人。

例如发现一个人既是另外一个人的孙子又是他的爸爸,这显然是不合伦理的,需要尽快发现并进行拨乱反正.

CREATE TABLE tree_cycle(ID INT, MgrID INT, Name VARCHAR(32));

INSERT INTO tree_cycle VALUES (1,NULL,'Kim');

INSERT INTO tree_cycle VALUES (2,11,'Moy');

INSERT INTO tree_cycle VALUES (3,1,'Jonas');

INSERT INTO tree_cycle VALUES (4,1,'Smith');

INSERT INTO tree_cycle VALUES (5,3,'Verma');

INSERT INTO tree_cycle VALUES (6,3,'Foster');

INSERT INTO tree_cycle VALUES (7,4,'Brown');

INSERT INTO tree_cycle VALUES (8,4,'Lin');

INSERT INTO tree_cycle VALUES (9,2,'Edwin');

INSERT INTO tree_cycle VALUES (10,9,'Audrey');

INSERT INTO tree_cycle VALUES (11,10,'Stone');

-- Checking a CONNECT_BY_ISCYCLE value

SELECT id, mgrid, name, CONNECT_BY_ISCYCLE

FROM tree_cycle

START WITH name in ('Kim', 'Moy')

CONNECT BY NOCYCLE PRIOR id=mgrid

ORDER BY id;

id mgrid name connect_by_iscycle

1 NULL 'Kim' 0

2 11 'Moy' 0

3 1 'Jonas' 0

4 1 'Smith' 0

5 3 'Verma' 0

6 3 'Foster' 0

7 4 'Brown' 0

8 4 'Lin' 0

9 2 'Edwin' 0

10 9 'Audrey' 0

11 10 'Stone' 1

CONNECT_BY_ROOT 关键字

同一个节点下的节点的connect_by_root是一样的

SELECT id, mgrid, name, CONNECT_BY_ROOT id

FROM tree

START WITH mgrid IS NULL

CONNECT BY PRIOR id=mgrid

ORDER BY id;

PRIOR关键字

下面的说明来自oracle

运算符PRIOR被放置于等号前后的位置,决定着查询时的检索顺序。

PRIOR被置于CONNECT BY子句中等号的前面时,则强制从根节点到叶节点的顺序检索,即由父节点向子节点方向通过树结构,我们称之为自顶向下的方式。如:

CONNECT BY PRIOR EMPNO=MGR

PIROR运算符被置于CONNECT BY 子句中等号的后面时,则强制从叶节点到根节点的顺序检索,即由子节点向父节点方向通过树结构,我们称之为自底向上的方式。例如:

CONNECT BY EMPNO=PRIOR MGR

在这种方式中也应指定一个开始的节点。

官方例子

SELECT id, mgrid, name, PRIOR id as "prior_id"

FROM tree

START WITH mgrid IS NULL

CONNECT BY PRIOR id=mgrid

ORDER BY id;

id mgrid name prior_id

1         NULL  'Kim'                        NULL
2 NULL 'Moy' NULL
3 1 'Jonas' 1
4 1 'Smith' 1
5 2 'Verma' 2
6 2 'Foster' 2
7 6 'Brown' 6 SYS_CONNECT_BY_PATH
SYS_CONNECT_BY_PATH (column_name, separator_char)
主要用于树查询(层次查询) 以及 多列转行 SELECT id, mgrid, name, SYS_CONNECT_BY_PATH(name,'/') as [hierarchy]

FROM tree

START WITH mgrid IS NULL

CONNECT BY PRIOR id=mgrid

ORDER BY id;

id mgrid name hierarchy

1         NULL  'Kim'                 '/Kim'
2 NULL 'Moy' '/Moy'
3 1 'Jonas' '/Kim/Jonas'
4 1 'Smith' '/Kim/Smith'
5 2 'Verma' '/Moy/Verma'
6 2 'Foster' '/Moy/Foster'
7 6 'Brown' '/Moy/Foster/Brown' 单元练习例子
CREATE TABLE tbl(seq INT, id VARCHAR(10), parent VARCHAR(10));

INSERT INTO tbl VALUES (1, 'a', null);

INSERT INTO tbl VALUES (2, 'b', 'a');

INSERT INTO tbl VALUES (3, 'b', 'c');

INSERT INTO tbl VALUES (4, 'c', 'b');

INSERT INTO tbl VALUES (5, 'c', 'b');

SELECT seq, id, parent, LEVEL,

CONNECT_BY_ISCYCLE AS iscycle,

CAST(SYS_CONNECT_BY_PATH(id,'/') AS VARCHAR(10)) AS idpath

FROM tbl

START WITH PARENT is NULL

CONNECT BY NOCYCLE PARENT = PRIOR id;

seq id parent level iscycle idpath

  1  'a'          NULL             1            0  '/a'
2 'b' 'a' 2 0 '/a/b'
4 'c' 'b' 3 0 '/a/b/c'
3 'b' 'c' 4 1 '/a/b/c/b'
5 'c' 'b' 5 1 '/a/b/c/b/c'
5 'c' 'b' 3 0 '/a/b/c'
3 'b' 'c' 4 1 '/a/b/c/b'
4 'c' 'b' 5 1 '/a/b/c/b/c' 今天之后是明天,明天之后是后天,后天之后是大后天 SELECT TO_CHAR(base_month + lvl -1, 'YYYYMMDD') h_date

FROM (

SELECT LEVEL lvl, base_month

FROM (

SELECT TO_DATE('201303', 'YYYYMM') base_month FROM db_root

)

CONNECT BY LEVEL <= LAST_DAY(base_month) - base_month + 1

);

h_date

'20130301'

'20130302'

'20130303'

'20130304'

'20130305'

'20130306'

'20130307'

'20130308'

'20130309'

'20130310'

'20130311'

'20130312'

'20130313'

'20130314'

'20130315'

'20130316'

'20130317'

'20130318'

'20130319'

'20130320'

'20130321'

'20130322'

'20130323'

'20130324'

'20130325'

'20130326'

'20130327'

'20130328'

'20130329'

'20130330'

'20130331'

CUBRID学习笔记 42 Hierarchical QuerySQL层级查询的更多相关文章

  1. CUBRID学习笔记 47 show

    cubrid的中sql查询语法show c#,net,cubrid,教程,学习,笔记欢迎转载 ,转载时请保留作者信息.本文版权归本人所有,如有任何问题,请与我联系wang2650@sohu.com . ...

  2. CUBRID学习笔记 48查询优化

    cubrid的中sql查询语法 查询优化 c#,net,cubrid,教程,学习,笔记欢迎转载 ,转载时请保留作者信息.本文版权归本人所有,如有任何问题,请与我联系wang2650@sohu.com ...

  3. CUBRID学习笔记 46 PREPARED set Do

    cubrid的中sql查询语法PREPARED set Do c#,net,cubrid,教程,学习,笔记欢迎转载 ,转载时请保留作者信息.本文版权归本人所有,如有任何问题,请与我联系wang2650 ...

  4. CUBRID学习笔记 45 REPLACE DELETE MERGE 教程

    c#,net,cubrid,教程,学习,笔记欢迎转载 ,转载时请保留作者信息.本文版权归本人所有,如有任何问题,请与我联系wang2650@sohu.com . 过错 ------ 官方文档是英文的, ...

  5. CUBRID学习笔记 44 UPDATE 触发器 更新多表 教程

    cubrid的中sql查询语法UPDATE c#,net,cubrid,教程,学习,笔记欢迎转载 ,转载时请保留作者信息.本文版权归本人所有,如有任何问题,请与我联系wang2650@sohu.com ...

  6. CUBRID学习笔记 43 insert into

    cubrid的中sql查询语法insert into ------ 官方文档是英文的,看不明白可以参看ocracle的同类函数说明.很多都是一样的. INSERT INTO a_tbl1(id) VA ...

  7. CUBRID学习笔记 41 sql语法之select

    cubrid的中sql查询语法 SELECT [ ] [{TO | INTO} ][FROM ] [WHERE ][GROUP BY {col_name | expr} [ASC | DESC], . ...

  8. CUBRID学习笔记 3 net连接数据库并使用cubrid教程示例

    接上文 数据库安装好后,也可以测试语句了. 下面我们用c#写一个控制台程序,连接数据库,并读取数据. 一 下载驱动  net版的下 CUBRID ADO.NET Data Provider 9.3.0 ...

  9. CUBRID学习笔记 2 安装教程

    下载地址  http://www.cubrid.org/?mid=downloads&item=any&os=detect&cubrid=9.3.0 选择适合你的服务器版本 l ...

随机推荐

  1. python PIL安装

    PIL:Python Imaging Library,已经是Python平台事实上的图像处理标准库了.PIL功能非常强大,但API却非常简单易用. 安装PIL 在Debian/Ubuntu Linux ...

  2. python中遇到的各种问题

    一 编码问题 python的默认编码是ascii码,可以修改为utf-8 在python\Lib\site-packages\下添加一个文件sitecustomize.py 内容是 import sy ...

  3. 【python】__future__模块

    转自:http://www.jb51.net/article/65030.htm Python的每个新版本都会增加一些新的功能,或者对原来的功能作一些改动.有些改动是不兼容旧版本的,也就是在当前版本运 ...

  4. 160918、BigDecimal运算

    java.math.BigDecimal.BigDecimal一共有4个够造方法,让我先来看看其中的两种用法: 第一种:BigDecimal(double val)Translates a doubl ...

  5. Hadoop三种安装模式:单机模式,伪分布式,真正分布式

    Hadoop三种安装模式:单机模式,伪分布式,真正分布式 一 单机模式standalone单 机模式是Hadoop的默认模式.当首次解压Hadoop的源码包时,Hadoop无法了解硬件安装环境,便保守 ...

  6. SQL算术数字的默认类型

    select 100*100*100*100*100 --错误:将 expression 转换为数据类型 int 时出现算术溢出错误. select   cast(1000 as  bigint) * ...

  7. VC中常用的宏

        我们在VS环境中开发的时候,会遇到很多宏定义,这些宏可以应用到代码中,或用于编译.工程选项等设置,总之是我们开发中必不可少的工具,有必要做一个总结.有些宏是C/C++定义的,有些宏是VC环境预 ...

  8. Python查看函数代码内容

    方法1:使用help(random) >>> import random >>> help(random) Help on module random: NAME ...

  9. Python包管理工具介绍

    常见的包管理工具及关系 setuptools -->distribute easy_install-->pip 1.distribute distribute是对标准库disutils模块 ...

  10. ACE的接受器(Acceptor)和连接器(Connector):连接建立模式

    ACE_Acceptor工厂的open()方法,或是它的缺省构造器(它实际上会调用open()方法),来开始被动侦听连接.当接受器工厂的open()方法被调用时,如果反应堆单体还没有被实例化,open ...