国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 數據庫 > MySQL > 正文

MySQL存儲過程實現Oracle鄰接模型樹形處理的方法實例

2024-07-24 12:35:04
字體:
來源:轉載
供稿:網友
  項目需求用到了鄰接模型,但是是采用開源的Mysql,而Mysql沒有這個功能,Oracle數據庫提供了現在的分析方法 connect by 處理鄰接模型,不過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));
  
  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  
  --phpfensi.com
  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>。
 

(編輯:武林網)

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 龙陵县| 象山县| 安新县| 江城| 宜昌市| 镇康县| 长垣县| 湟中县| 东平县| 襄城县| 湖州市| 镇远县| 广安市| 梁平县| 蕲春县| 施甸县| 丹东市| 宁明县| 松江区| 望谟县| 四子王旗| 平罗县| 十堰市| 兰西县| 香格里拉县| 西丰县| 县级市| 北京市| 呼和浩特市| 同仁县| 昌江| 洞头县| 芷江| 甘洛县| 新郑市| 宿州市| 马龙县| 筠连县| 修文县| 宁乡县| 修文县|