oracle怎么使用递归 oracle向下递归

oracle触发器递归

一 触发器介绍

专注于为中小企业提供成都网站设计、网站建设服务,电脑端+手机端+微信端的三站合一,更高效的管理,为中小企业北京免费做网站提供优质的服务。我们立足成都,凝聚了一批互联网行业人才,有力地推动了近千家企业的稳健成长,帮助中小企业通过网站建设实现规模扩充和转变。

触发器是一种特殊的存储过程,它在插入,删除或修改特定表中的数据时触发执行,它比数据库本身标准的功能有更精细和更复杂的数据控制能力。数据库触发器有以下的作用:

* 安全性。可以基于数据库的值使用户具有操作数据库的某种权利。

# 可以基于时间限制用户的操作,例如不允许下班后和节假日修改数据库数据。

# 可以基于数据库中的数据限制用户的操作,例如不允许股票的价格的升幅一次超过10%。

* 审计。可以跟踪用户对数据库的操作。

# 审计用户操作数据库的语句。

# 把用户对数据库的更新写入审计表。

* 实现复杂的数据完整性规则。

# 实现非标准的数据完整性检查和约束。触发器可产生比规则更为复杂的限制。与规则不同,触发器可以引用列或数据库对象。例如,触发器可回退任何企图吃进超过自己保证金的期货。

# 提供可变的缺省值。

* 实现复杂的非标准的数据库相关完整性规则。触发器可以对数据库中相关的表进行连环更新。例如,在auths表author_code列上的删除触发器可导致相应删除在其它表中的与之匹配的行。

# 在修改或删除时级联修改或删除其它表中的与之匹配的行。

# 在修改或删除时把其它表中的与之匹配的行设成NULL值。

# 在修改或删除时把其它表中的与之匹配的行级联设成缺省值。

# 触发器能够拒绝或回退那些破坏相关完整性的变化,取消试图进行数据更新的事务。当插入一个与其主健不匹配的外部键时,这种触发器会起作用。例如,可以在 books.author_code列上生成一个插入触发器,如果新值与auths.author_code列中的某值不匹配时,插入被回退。

* 同步实时地复制表中的数据。

* 自动计算数据值,如果数据的值达到了一定的要求,则进行特定的处理。例如,如果公司的帐号上的资金低于5万元则立即给财务人员发送警告数据。

ORACLE与SYBASE数据库的触发器有一定的区别,下面将分别讲述这两种数据库触发器的作用和写法。

二 ORACLE 触发器

ORACLE产生数据库触发器的语法为:

create [or replace] trigger 触发器名 触发时间 触发事件

on 表名

[for each row]

pl/sql 语句

其中:

触发器名:触发器对象的名称。由于触发器是数据库自动执行的,因此该名称只是一个名称,没有实质的用途。

触发时间:指明触发器何时执行,该值可取:

before---表示在数据库动作之前触发器执行;

after---表示在数据库动作之后出发器执行。

触发事件:指明哪些数据库动作会触发此触发器:

insert:数据库插入会触发此触发器;

update:数据库修改会触发此触发器;

delete:数据库删除会触发此触发器。

表 名:数据库触发器所在的表。

for each row:对表的每一行触发器执行一次。如果没有这一选项,则只对整个表执行一次。

举例:下面的触发器在更新表auths之前触发,目的是不允许在周末修改表:

create trigger auth_secure

before insert or update or delete //对整表更新前触发

on auths

begin

if(to_char(sysdate,'DY')='SUN'

RAISE_APPLICATION_ERROR(-20600,'不能在周末修改表auths');

end if;

end

三 SYBASE数据库触发器

SYBASE数据库触发器的作用与ORACLE非常类似,仅有较小的差异。

SYBASE产生触发器的语法为:

CREATE TRIGGER 触发器名

ON 表名

FOR INSERT,UPDATE,DELETE

AS

SQL_statement |

FOR INSERT,UPDATE

AS

IF UPDATE(column_name) [AND|OR UPDATE(column_name)]...

SQL_statements

上面FOR子句用来指定在触发器上的哪些数据更新命令可激活该触发器。IF UPDATE子句检查对指定列的操作类型,在IF UPDATE子句中可指定多个列。

与ORACLE不同,对于每条SQL语句,触发器只执行一次。触发器在数据更新语句完成以后立即执行。触发器和启动它的语句被当作一个事务处理,事务可以在触发器中回退。

下面举例说明SYBASE触发器的写法。

create trigger forinsert_books

on books

for insert

as

if(select count(*) from auths,inserted

where auths.author_code=insert.author_code)!=@@rowcount

begin

rollback transaction

print "books 表中 author_code 列的值在auths 表中不存在。"

ORACLE递归

about connect by

SELECT empno, ename, job, mgr, deptno, LEVEL, sys_connect_by_path(ename,'\'), connect_by_root(ename) FROM emp START WITH mgr IS NULL CONNECT BY mgr =  PRIOR empno

WITH T(empno, ename, job, mgr, deptno, the_level, path,top_manager) AS ( ---- 必须把结构写出来

SELECT empno, ename, job, mgr, deptno  ---- 先写锚点查询,用START WITH的条件

,1 AS the_level    ---- 递归起点,第一层

,'\'||ename        ---- 路径的第一截

,ename AS top_manager ---- 原来的CONNECT_BY_ROOT

FROM scott.EMP

WHERE mgr IS NULL ---- 原来的START WITH条件

UNION ALL  ---- 下面是递归部分

SELECT e.empno, e.ename, e.job, e.mgr, e.deptno  ---- 要加入的新一层数据,来自要遍历的emp表

,1 + t.the_level            ---- 递归层次,在原来的基础上加1。这相当于CONNECT BY查询中的LEVEL伪列

,t.path||'\'||e.ename        ---- 把新的一截路径拼上去

,t.top_manager              ---- 直接继承原来的数据,因为每个路径的根节点只有一个

FROM t, scott.emp e                    ---- 典型写法,把子查询本身和要遍历的表作一个连接

WHERE t.empno = e.mgr            ---- 原来的CONNECT BY条件

) ---- WITH定义结束

SELECT * FROM T

EMPNO ENAME      JOB        MGR DEPTNO  THE_LEVEL PATH                                                                            TOP_MANAGER

----- ---------- --------- ----- ------ ---------- -------------------------------------------------------------------------------- -----------

7839 KING      PRESIDENT          10          1 \KING                                                                            KING

7566 JONES      MANAGER    7839    20          2 \KING\JONES                                                                      KING

7698 BLAKE      MANAGER    7839    30          2 \KING\BLAKE                                                                      KING

7782 CLARK      MANAGER    7839    10          2 \KING\CLARK                                                                      KING

7999 MIKE      ANALYST    7566    30          3 \KING\JONES\MIKE                                                                KING

7499 ALLEN      SALESMAN  7698    30          3 \KING\BLAKE\ALLEN                                                                KING

7521 WARD      SALESMAN  7698    30          3 \KING\BLAKE\WARD                                                                KING

7654 MARTIN    SALESMAN  7698    30          3 \KING\BLAKE\MARTIN                                                              KING

7788 SCOTT      ANALYST    7566    20          3 \KING\JONES\SCOTT                                                                KING

7844 TURNER    SALESMAN  7698    30          3 \KING\BLAKE\TURNER                                                              KING

7900 JAMES      CLERK      7698    30          3 \KING\BLAKE\JAMES                                                                KING

7902 FORD      ANALYST    7566    20          3 \KING\JONES\FORD                                                                KING

7934 MILLER    CLERK      7782    10          3 \KING\CLARK\MILLER                                                              KING

7369 SMITH      CLERK      7902    20          4 \KING\JONES\FORD\SMITH                                                          KING

7876 ADAMS      CLERK      7788    20          4 \KING\JONES\SCOTT\ADAMS                                                          KING

oracle 存储过程 递归实现 依赖分析

下面是用oracle数据库解决不用start with 来查询子父数据查询方法,里面主要用到了substr 和instr 函数(这两个函数,其他数据库也有相对应的函数),游标(其他数据库也有游标)。

-- 1 前提:创建表以及插入数据

CREATE TABLE TMP_TEST(MAIN_COLUMN VARCHAR2(10),PARENT_COLUMN VARCHAR2(10));

INSERT INTO TMP_TEST(MAIN_COLUMN,PARENT_COLUMN) VALUES('A',NULL);

INSERT INTO TMP_TEST(MAIN_COLUMN,PARENT_COLUMN) VALUES('B','A');

INSERT INTO TMP_TEST(MAIN_COLUMN,PARENT_COLUMN) VALUES('C','A');

INSERT INTO TMP_TEST(MAIN_COLUMN,PARENT_COLUMN) VALUES('D','A');

INSERT INTO TMP_TEST(MAIN_COLUMN,PARENT_COLUMN) VALUES('E','B');

INSERT INTO TMP_TEST(MAIN_COLUMN,PARENT_COLUMN) VALUES('F','C');

INSERT INTO TMP_TEST(MAIN_COLUMN,PARENT_COLUMN) VALUES('G','E');

-- 2 创建存储过程

CREATE OR REPLACE PROCEDURE GET_TREE(IS_PARENT   IN NUMBER /** 子父查询 **/,

SEARCH_ID   IN VARCHAR2 /** 查询条件节点 **/,

TREE_RESOUT OUT VARCHAR2 /** 输出结果集合 **/)

AS

V_TEMP VARCHAR2(4000);

V_SEARCH VARCHAR2(4000);

V_INDEX INTEGER;

BEGIN

V_TEMP :=SEARCH_ID||'-';

TREE_RESOUT := '';

WHILE length(V_TEMP) 0 LOOP

V_INDEX := instr(V_TEMP,'-');

V_SEARCH := substr(V_TEMP,0,V_INDEX-1);

V_TEMP := substr(V_TEMP,V_INDEX+1);

/*DBMS_OUTPUT.put_line('V_INDEX:'|| V_INDEX ||'V_TEMP:' ||V_TEMP||'V_SEARCH:'|| V_SEARCH);*/

/** 查询子节点 **/

if(IS_PARENT = 1) THEN

FOR C1 IN (SELECT * FROM TMP_TEST T1 WHERE T1.PARENT_COLUMN = V_SEARCH) LOOP

TREE_RESOUT := TREE_RESOUT || C1.MAIN_COLUMN;

V_TEMP := V_TEMP || C1.MAIN_COLUMN || '-';

END LOOP;

ELSE

/** 查询父节点 **/

FOR C1 IN (SELECT * FROM TMP_TEST T1 WHERE T1.MAIN_COLUMN = V_SEARCH) LOOP

TREE_RESOUT := TREE_RESOUT || C1.PARENT_COLUMN;

V_TEMP := V_TEMP || C1.PARENT_COLUMN || '-';

END LOOP;

END IF;

END LOOP;

/*DBMS_OUTPUT.put_line('TREE_RESOUT:'||TREE_RESOUT);*/

END;

-- 3 调用存储过程

declare

TREE_RESULT VARCHAR2(4000);

SEARCH_ID VARCHAR2(4000);

begin

get_tree(1,'A',TREE_RESULT);

dbms_output.put_line('查询子节点:' || TREE_RESULT);

get_tree(0,'G',TREE_RESULT);

dbms_output.put_line('查询父节点:' || TREE_RESULT);

end;

ORACLE select 递归查询

START WITH 定义数据行查询的初始起点;

CONNECT BY prior 定义表中的各个行是如何联系的;

connect by 后面的"prior" 如果缺省,则只能查询到符合条件的起始行,并不进行递归查询;

条件2:col_1 = col_2,col_1是父键(它标识父),col_2是子键(它标识子)。

条件3过滤递归前相应节点及其子节点,如果上级节点不满足则下级节点自动过滤掉;

条件4过滤递归后相应的节点或子节点,如果上级节点不满足则下级结点自动提升一级。

系统伪列:

CURRVAL AND NEXTVAL 使用序列号的保留字

ROWID 记录的唯一标识

ROWNUM 限制查询结果集的数量

LEVEL 显示层次树中特定行的层次或级别

CONNECT_BY_ROOT 返回当前层的根节点(当前行数据所对应的最高等级节点的内容)

SYS_CONNECT_BY_PATH(column, char) 函数实现将从父节点到当前行内容以"path"或者层次元素列表的形式显示出来

CONNECT_BY_ISCYCLE 须带参数NOCYCLE,当前行中引用了某个父亲节点的内容并在树中出现了循环,如果循环显示"1",否则就显示"0"。

CONNECT_BY_ISLEAF 判断当前行是不是叶子。如果是叶子显示"1",如果不是叶子而是一个分支(例如当前内容是其他行的父亲)就显示"0"

而在 Oracle 10g 中,只要指定"NOCYCLE"就可以进行任意的查询操作。与这个关键字相关的还有一个伪列——CONNECT_BY_ISCYCLE, 如果在当前行中引用了某个父亲节点的内容并在树中出现了循环,那么该行的伪列中就会显示"1",否则就显示"0"。

【实例】

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

create table test(superid varchar2(20),id varchar2(20),mc varchar2(20));

insert into test values('0','1','A1');

insert into test values('0','2','A2');

insert into test values('1','11','A11');

insert into test values('1','12','A12');

insert into test values('2','21','A21');

insert into test values('2','22','A22');

insert into test values('11','111','A111');

insert into test values('11','112','A112');

insert into test values('12','121','A121');

insert into test values('12','122','A122');

insert into test values('21','211','A211');

insert into test values('21','212','A212');

insert into test values('22','221','A221');

insert into test values('22','222','A222');

commit;

--层次查询示例

select level||'级' jc,lpad(' ',(level-1)*4)||id id,mc

from test

start with superid = '0' connect by prior id=superid;

select level||'级' jc,connect_by_isleaf mxf,lpad(' ',(level-1)*4)||id id,mc

from test

start with superid = '0' connect by prior id=superid;

--给出两个以前在"数据库字符串分组相加之四"中的例子来理解start with ... connect by ...

--功能:实现按照superid分组,把id用";"连接起来

--实现:以下两个例子都是通过构造2个伪列来实现connect by连接的。

Oracle递归查询:使用prior实现树操作

select * from tableName

start with  条件A   -- 开始递归的根节点,可多个条件

connect  by prior  条件B  -- prior  决定查询的索引顺序

where 条件 C

select t.empno,t.mgr,t.deptno ,level

from emp t

connect by prior t.empno=t.mgr

order by level,t.mgr,t.deptno;

找到empno为7369的所有领导。

select t.*,t.rowid from emp t

start with t.empno = 7369       --从empno为7369的开始查找

connect by prior t.mgr = t.empno ;    --上一条数据(这里就是empno为7369)的mgr == 当前遍历这一条数据的empno(那么就会找到empno为7902的用户)

找到empno为7566的所有下属

select t.*,t.rowid from emp t

start with t.empno = 7566

connect by prior t.empno = t.mgr ; --注意:connect by  t.mgr =prior t.empno与左边写法含义一样

start with :设置起点,省略后默认以全部行为起点。

connect by [condition] :与一般的条件一样作用于当前列,但是在满足条件后,会以全部列作为下一层级递归(没有其他条件的话)。

prior : 表示上一层级的标识符。经常用来对下一层级的数据进行限制。不可以接伪列。

level :伪列,表示当前深度。

connect_by_root() :显示根节点列。经常用来分组。

connect_by_isleaf :1是叶子节点,0不是叶子节点。在制作树状表格时必用关键字。

sys_connect_by_path() :将递归过程中的列进行拼接。

nocycle , connect_by_iscycle : 在有循环结构的查询中使用。

siblings : 保留树状结构,对兄弟节点进行排序

;request_id=162538763316780265474850biz_id=0utm_medium=distribute.pc_search_result.none-task-blog-2~all~first_rank_v2~rank_v29-22-52652111.first_rank_v2_pc_rank_v29_1utm_term=ORACLE%E9%80%92%E5%BD%92%E5%87%BD%E6%95%B0spm=1018.2226.3001.4187

;request_id=162538763316780269872688biz_id=0utm_medium=distribute.pc_search_result.none-task-blog-2~all~baidu_landing_v2~default-5-108683534.first_rank_v2_pc_rank_v29_1utm_term=ORACLE%E9%80%92%E5%BD%92%E5%87%BD%E6%95%B0spm=1018.2226.3001.4187

;request_id=162538763316780265474850biz_id=0utm_medium=distribute.pc_search_result.none-task-blog-2~all~first_rank_v2~rank_v29-10-105773226.first_rank_v2_pc_rank_v29_1utm_term=ORACLE%E9%80%92%E5%BD%92%E5%87%BD%E6%95%B0spm=1018.2226.3001.4187


文章标题:oracle怎么使用递归 oracle向下递归
文章分享:http://myzitong.com/article/hjjegc.html