MySQL存储过程实现Oracle邻接模型树形处理的方法实例

数据库对层次结构的处理模型有好多种,可以根据自己的需求来设计模型,当然最简单的也是最容易设计的模型就是所谓的邻接模型。在这方面,其他数据库比如Oracle 提供了现成的分析方法 connect by,而MySQL在这方面就显得有些薄弱了。 不过可以用MySQL的存储过程实现ORACLE类似的分析功能

这样,先来创建一个简单的数表。

 代码如下 复制代码

create table country ( id number(2) not null, name varchar(60) not null);
create table country_relation (id number(2), parentid number(2));

插入一些数据

 代码如下 复制代码

-- Table country.
insert into country (id,name) values (0,'Earth');
insert into country (id,name) values (2,'North America');
insert into country (id,name) values (3,'South America');
insert into country (id,name) values (4,'Europe');
insert into country (id,name) values (5,'Asia');
insert into country (id,name) values (6,'Africa');
insert into country (id,name) values (7,'Australia');
insert into country (id,name) values (8,'Canada');
insert into country (id,name) values (9,'Central America');
insert into country (id,name) values (10,'Island Nations');
insert into country (id,name) values (11,'United States');
insert into country (id,name) values (12,'Alabama');
insert into country (id,name) values (13,'Alaska');
insert into country (id,name) values (14,'Arizona');
insert into country (id,name) values (15,'Arkansas');
insert into country (id,name) values (16,'California');

-- Table country_relation.
insert into country_relation (id,parentid) values (0,NULL);
insert into country_relation (id,parentid) values (2,0);
insert into country_relation (id,parentid) values (3,0);
insert into country_relation (id,parentid) values (4,0);
insert into country_relation (id,parentid) values (5,0);
insert into country_relation (id,parentid) values (6,0);
insert into country_relation (id,parentid) values (7,0);
insert into country_relation (id,parentid) values (8,2);
insert into country_relation (id,parentid) values (9,2);
insert into country_relation (id,parentid) values (10,2);
insert into country_relation (id,parentid) values (11,2);
insert into country_relation (id,parentid) values (12,11);
insert into country_relation (id,parentid) values (13,11);
insert into country_relation (id,parentid) values (14,11);
insert into country_relation (id,parentid) values (15,11);
insert into country_relation (id,parentid) values (16,11);

在Oracle 里面,对这些操作就比较简单了,都是系统提供的。
比如下面四种情形:
1). 查看深度,

 代码如下 复制代码

select max(level) "level" from COUNTRY_RELATION a start with a.parentid is NULL
connect by PRIOR a.id = a.PARENTID
order by level;

     level
----------
         4

已用时间: 00: 00: 00.03

2). 查看叶子节点

 代码如下 复制代码

select name from
(
select b.name, connect_by_isleaf "isleaf"
from COUNTRY_RELATION a inner join country b on (a.id = b.id)
start with a.parentid is NULL connect by prior a.id = a.PARENTID
) T where T."isleaf" = 1;

NAME
--------------------------------------------------
Canada
Central America
Island Nations
Alabama
Alaska
Arizona
Arkansas
California
South America
Europe
Asia
Africa
Australia

已选择13行。

已用时间: 00: 00: 00.01

3) 查看ROOT节点

 代码如下 复制代码

select connect_by_root b.name
from COUNTRY_RELATION a inner join country b on (a.id = b.id)
start with a.parentid is NULL connect by a.id = a.PARENTID

CONNECT_BY_ROOTB.NAME
--------------------------------------------------
Earth

已用时间: 00: 00: 00.01

4). 查看路径

 代码如下 复制代码

select sys_connect_by_path(b.name,'/') "path"
from COUNTRY_RELATION a inner join country b on (a.id = b.id)
start with a.parentid is NULL connect by prior a.id = a.PARENTID
order by level,a.id;

path
--------------------------------------------------
/Earth
/Earth/North America
/Earth/South America
/Earth/Europe
/Earth/Asia
/Earth/Africa
/Earth/Australia
/Earth/North America/Canada
/Earth/North America/Central America
/Earth/North America/Island Nations
/Earth/North America/United States
/Earth/North America/United States/Alabama
/Earth/North America/United States/Alaska
/Earth/North America/United States/Arizona
/Earth/North America/United States/Arkansas
/Earth/North America/United States/California

已选择16行。

已用时间: 00: 00: 00.01

接下来我们看看在MySQL 里面如何实现上面四种情形:
前三种都比较简单,可以很容易写出SQL。
1)查看深度

 代码如下 复制代码

mysql> SELECT COUNT(DISTINCT IFNULL(parentid,-1)) AS LEVEL FROM country_relation
;
+-------+
| LEVEL |
+-------+
| 4 |
+-------+
1 row in set (0.00 sec)

2)查看ROOT节点

 代码如下 复制代码

mysql> SELECT b.`name` AS root_node FROM
    -> (
    -> SELECT id FROM country_relation WHERE parentid IS NULL
    -> ) AS a, country AS b WHERE a.id = b.id;
+-----------+
| root_node |
+-----------+
| Earth |
+-----------+
1 row in set (0.00 sec)

3).  查看叶子节点

 代码如下 复制代码

mysql> SELECT b.`name` AS leaf_node FROM
    -> (
    -> SELECT id FROM country_relation WHERE id NOT IN (SELECT IFNULL(parentid,
-1) FROM country_relation)
    -> ) AS a, country AS b WHERE a.id = b.id;
+-----------------+
| leaf_node |
+-----------------+
| South America |
| Europe |
| Asia |
| Africa |
| Australia |
| Canada |
| Central America |
| Island Nations |
| Alabama |
| Alaska |
| Arizona |
| Arkansas |
| California |
+-----------------+
13 rows in set (0.00 sec)

mysql>

4) 查看路径
这一块没有简单的SQL实现,不过可以用MySQL的存储过程来实现同样的功能。
存储过程代码如下:

 代码如下 复制代码

DELIMITER $$

USE `t_girl`$$

DROP PROCEDURE IF EXISTS `sp_show_list`$$

CREATE DEFINER=`root`@`localhost` PROCEDURE `sp_show_list`()
BEGIN
      -- Created by ytt 2014/11/04.
      -- Is equal to oracle's connect by syntax.
      -- Body.
      DROP TABLE IF EXISTS tmp_country_list;
      CREATE TEMPORARY TABLE tmp_country_list (node_level INT UNSIGNED NOT NULL, node_path VARCHAR(1000) NOT NULL);
      -- Get the root node.
      INSERT INTO tmp_country_list SELECT 1, CONCAT('/',id) FROM country_relation WHERE parentid IS NULL;
      -- Loop within all parent node.
      cursor1:BEGIN
        DECLARE done1 INT DEFAULT 0;
        DECLARE i1 INT DEFAULT 1;
        DECLARE v_parentid INT DEFAULT -1;
        DECLARE v_node_path VARCHAR(1000) DEFAULT '';
        DECLARE cr1 CURSOR FOR SELECT parentid FROM country_relation WHERE parentid IS NOT NULL GROUP BY parentid ORDER BY parentid ASC;
        DECLARE CONTINUE HANDLER FOR NOT FOUND SET done1 = 1;
       
        OPEN cr1;
       
        loop1:LOOP
          FETCH cr1 INTO v_parentid;
          IF done1 = 1 THEN
            LEAVE loop1;
          END IF;
          SET i1 = i1 + 1;
         
          label_path:BEGIN
            DECLARE done2 INT DEFAULT 0;
            DECLARE CONTINUE HANDLER FOR NOT FOUND SET done2 = 1;
            -- Get the upper path.
            SELECT node_path FROM tmp_country_list WHERE node_level = i1 - 1 AND LOCATE(v_parentid,node_path) > 0 INTO v_node_path;
            -- Escape the outer not found exception.
            IF done2 = 1 THEN
              SET done2 = 0;
            END IF;
            INSERT INTO tmp_country_list
            SELECT i1,CONCAT(IFNULL(v_node_path,''),'/',id) FROM country_relation WHERE parentid = v_parentid;
          END;
        END LOOP;
       
        CLOSE cr1;
       
      END;
      -- Update node's id to its real name.
      update_name_label:BEGIN
        DECLARE cnt INT DEFAULT 0;
        DECLARE i2 INT DEFAULT 0;
        SELECT MAX(node_level) FROM tmp_country_list INTO cnt;
        WHILE i2 < cnt
        DO
          UPDATE tmp_country_list AS a, country AS b
          SET a.node_path = REPLACE(a.node_path,CONCAT('/',b.id),CONCAT('/',b.name))
          WHERE LOCATE(CONCAT('/',b.id),a.node_path) > 0;
          SET i2 = i2 + 1;
        END WHILE;
      END;
    
     SELECT node_path FROM tmp_country_list;
    END$$

DELIMITER ;

调用结果:

 代码如下 复制代码

mysql> CALL sp_show_list();
+-----------------------------------------------+
| node_path |
+-----------------------------------------------+
| /Earth |
| /Earth/North America |
| /Earth/South America |
| /Earth/Europe |
| /Earth/Asia |
| /Earth/Africa |
| /Earth/Australia |
| /Earth/North America/Canada |
| /Earth/North America/Central America |
| /Earth/North America/Island Nations |
| /Earth/North America/United States |
| /Earth/North America/United States/Alabama |
| /Earth/North America/United States/Alaska |
| /Earth/North America/United States/Arizona |
| /Earth/North America/United States/Arkansas |
| /Earth/North America/United States/California |
+-----------------------------------------------+
16 rows in set (0.04 sec)

Query OK, 0 rows affected (0.08 sec)

mysql>

时间: 2024-09-05 05:30:05

MySQL存储过程实现Oracle邻接模型树形处理的方法实例的相关文章

MySQL存储过程中实现执行动态SQL语句的方法_Mysql

本文实例讲述了MySQL存储过程中实现执行动态SQL语句的方法.分享给大家供大家参考.具体实现方法如下: mysql> mysql> delimiter $$ mysql> mysql> CREATE PROCEDURE set_col_value -> (in_table VARCHAR(128), -> in_column VARCHAR(128), -> in_new_value VARCHAR(1000), -> in_where VARCHAR(4

mysql存储过程查看,修改,删除,创建方法

mysql教程存储过程查看,修改,删除,创建方法 文章主要简单的介绍关于mysql存储过程查看,修改,删除,创建的方法哦,下面举了四个实例来证明一下关于存储过程的操作. 询数据库教程中的存储过程: 方法一:(直接查询) select `specific_name` from mysql.proc where db = 'your_db_name' and `type` = 'procedure' 方法二:(查看数据库里所有存储过程+内容) show procedure status; 方法三:(

php简单实现无限分类树形列表的方法

 这篇文章主要介绍了php简单实现无限分类树形列表的方法,实例分析了php通过数组实现树形列表的技巧,具有一定参考借鉴价值,需要的朋友可以参考下     本文实例讲述了php简单实现无限分类树形列表的方法.分享给大家供大家参考.具体如下: ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 $items = array( 1 => array('id'

数据库-新人:mysql存储过程求问

问题描述 新人:mysql存储过程求问 各位老师,由于工作需要,最近学了mysql.这段时间也看了许多有关存储过程的教程和案例.但还是摸不着头脑.这里要请教大家,mysql存储过程具体应该如何实现.(给我个大概得框架就行) 这里需要用manager_id=human_id这个条件,找出符合条件的thuman,就如我图3. 但是接下来还要用新求出来的thuman_id=human_id这个条件循环查询出manager下面的thuman信息. 这个本人认为要用到存储过程循环查询建表和插入.但由于个人

MySQL 存储过程初研究

最近在做一个移动设备多类型登录的统一用户系统.其中记录用户资料的部分,因为涉及到更换设备的相同用户.同一个用户多类型同时具备的情况,所以想分辨出尽量少的用户去合理记录,就需要多次查询.于是决定研究一下 MySQL 存储程序. MySQL 现在是 5.5 或者 5.6 .因为存储程序是 5.x 才具备的特性,所以放弃了具有中文文档的 5.1 ,选择可能会修改了很多问题的 5.5 .可惜这就造成我不得不去看在线英文文档,因为我实在找不到 MySQL 5.5 的 PDF 版中文文档-- 在线文档地址是

MySQL存储过程中一些基本的异常处理教程_Mysql

有时候,不希望存储过程抛出错误中止执行,而是希望返回一个错误码. Mysql 支持异常处理,通过定义 CONTINUE/EXIT 异常处理的 HANDLER 来捕获 SQLWARNING/NOT FOUND/SQLEXCEPTION (警告 / 无数据 / 其他异常).其中, FOR 后面可以改为 SQLWARNING, NOT FOUND, SQLEXCEPTION 来指示所有异常都处理,相当于 oracle 中的 others .例如,当不进行异常处理时,以下代码将直接抛出一个 ERROR

mysql 存储过程详解_Mysql

MySQL存储过程  14.1.1 创建存储过程 MySQL中,创建存储过程的基本形式如下: CREATE PROCEDURE sp_name ([proc_parameter[,...]])          [characteristic ...] routine_body 其中,sp_name参数是存储过程的名称:proc_parameter表示存储过程的参数列表: characteristic参数指定存储过程的特性:routine_body参数是SQL代码的内容,可以用BEGIN-END

mysql 存储过程使用说明详解

MySQL存储过程的优点 预编译,相对于直接的SQL效率会高点,同时可以降低SQL语句传输过程中消耗的流量: 简化业务逻辑,可以把需求转化给专业的DBA(如果有的话): 更方便的使用MySQL数据库事物的处理,尤其是购物类网站: 安全.用户权限更容易管理: 修改存储过程基本上不需要修改程序代码,而直接写SQL修改SQL一般都要修改相关的程序 mysql储存过程的创建等语句: 1.CREATE PROCEDURE (创建储存过程)    CREATE PROCEDURE 存储过程名 (参数列表)

CI调用存储过程很慢怎么提速,mysql存储过程本身执行很快,但是在php调用就要0.8s

问题描述 CI调用存储过程很慢怎么提速,mysql存储过程本身执行很快,但是在php调用就要0.8s $this -> db -> reconnect(); $mysqli = new mysqli(); $mysqli -> query(""SET NAMES utf8""); if (mysqli_connect_errno()) { printf('Connect failed: %s ' mysqli_connect_error()); e