2012-06-12 48 views
4

我有一個組織表,其中包含idparent_idname列。這張桌子裏大約有5萬行。只有一個頂級父母,其餘全部都在此之下。在Oracle中,我能夠很容易地與level虛列檢索特定組織的當前深度:MySQL - 鄰接列表模型 - 獲取深度

SELECT id, parent_id, level, name 
FROM organizations 
START WITH parent_id = 1 
CONNECT BY PRIOR id = parent_id 

我在做什麼上面在MySQL的正確方法是一種損失。我需要在一個查詢中獲取整個樹以及節點的深度。

在StackOverflow上有很多問題需要處理,但他們都沒有一個很好的答案,主要是鏈接到博客和可疑的解決方案。當然這可以以某種直接的方式進行?

不幸的是,以任何方式修改表不是一種選擇,所以嵌套集合是不可能的。

+0

[使用MySQL查詢來遍歷行以生成遞歸樹]的可能的重複(http://stackoverflow.com/questions/10646833/using-mysql-query-to-traverse-rows-to-make-a-遞歸樹) – RandomSeed

回答

2

在沒有CTEs/Subquery Factoring的SQL中沒有遞歸,因此在「Pure SQL」中特別且絕對沒有辦法使用任意級別的深度執行此操作,特別是在MySQL中實現時。見How to transform a MSSQL CTE query to MySQL?

這就是爲什麼你找到的所有答案都是黑客,以解決這個非常具體的引擎限制。如果你仍然需要這個解決方案,你可以試試這個解決方案:Generating Depth based tree from Hierarchical Data in MySQL (no CTEs)。 (當然,限制意味着在LangSec的意義上,查詢並不奇怪,它允許各種有益的解析,並消除一些安全問題,但是完全不會幫助你。)

一堆的Lefts Join s排除了層次結構是所有你已經離開,抱歉disapoint和使用壞的雙關語。

0

Mysql不支持遞歸sql。如果只有一個維度,則可以在parent_id = id上使用左連接。

4

這完全是搞笑的。我拿起一個+50賞金上類似的問題從字面上昨天:Using MySQL query to traverse rows to make a recursive tree

我引用how to do this with Stored Procedures in the DBA StackExchange(2011年10月24日)

我會後與我的DBA StackExchange答案的例子沿着相同的存儲過程:

代碼來獲取父對於任何給定節點

DELIMITER $$ 
DROP FUNCTION IF EXISTS `junk`.`GetParentIDByID` $$ 
CREATE FUNCTION `junk`.`GetParentIDByID` (GivenID INT) RETURNS INT 
DETERMINISTIC 
BEGIN 
    DECLARE rv INT; 

    SELECT IFNULL(parent_id,-1) INTO rv FROM 
    (SELECT parent_id FROM pctable WHERE id = GivenID) A; 
    RETURN rv; 
END $$ 
DELIMITER ; 

代碼來獲取Ancenstry對於任何給定節點

DELIMITER $$ 
DROP FUNCTION IF EXISTS `junk`.`GetAncestry` $$ 
CREATE FUNCTION `junk`.`GetAncestry` (GivenID INT) RETURNS VARCHAR(1024) 
DETERMINISTIC 
BEGIN 
    DECLARE rv VARCHAR(1024); 
    DECLARE cm CHAR(1); 
    DECLARE ch INT; 

    SET rv = ''; 
    SET cm = ''; 
    SET ch = GivenID; 
    WHILE ch > 0 DO 
     SELECT IFNULL(parent_id,-1) INTO ch FROM 
     (SELECT parent_id FROM pctable WHERE id = ch) A; 
     IF ch > 0 THEN 
      SET rv = CONCAT(rv,cm,ch); 
      SET cm = ','; 
     END IF; 
    END WHILE; 
    RETURN rv; 
END $$ 
DELIMITER ; 

代碼來獲取家譜(或後代)對於任何給定節點

DELIMITER $$ 

DROP FUNCTION IF EXISTS `junk`.`GetFamilyTree` $$ 
CREATE FUNCTION `junk`.`GetFamilyTree` (GivenID INT) RETURNS varchar(1024) CHARSET latin1 
DETERMINISTIC 
BEGIN 

    DECLARE rv,q,queue,queue_children VARCHAR(1024); 
    DECLARE queue_length,front_id,pos INT; 

    SET rv = ''; 
    SET queue = GivenID; 
    SET queue_length = 1; 

    WHILE queue_length > 0 DO 
     SET front_id = FORMAT(queue,0); 
     IF queue_length = 1 THEN 
      SET queue = ''; 
     ELSE 
      SET pos = LOCATE(',',queue) + 1; 
      SET q = SUBSTR(queue,pos); 
      SET queue = q; 
     END IF; 
     SET queue_length = queue_length - 1; 

     SELECT IFNULL(qc,'') INTO queue_children 
     FROM (SELECT GROUP_CONCAT(id) qc 
     FROM pctable WHERE parent_id = front_id) A; 

     IF LENGTH(queue_children) = 0 THEN 
      IF LENGTH(queue) = 0 THEN 
       SET queue_length = 0; 
      END IF; 
     ELSE 
      IF LENGTH(rv) = 0 THEN 
       SET rv = queue_children; 
      ELSE 
       SET rv = CONCAT(rv,',',queue_children); 
      END IF; 
      IF LENGTH(queue) = 0 THEN 
       SET queue = queue_children; 
      ELSE 
       SET queue = CONCAT(queue,',',queue_children); 
      END IF; 
      SET queue_length = LENGTH(queue) - LENGTH(REPLACE(queue,',','')) + 1; 
     END IF; 
    END WHILE; 

    RETURN rv; 

END $$ 

爲了證明一切的執行,這裏是樣本數據

USE junk 
DROP TABLE IF EXISTS pctable; 
CREATE TABLE pctable 
(
    id INT NOT NULL AUTO_INCREMENT, 
    parent_id INT, 
    PRIMARY KEY (id) 
) ENGINE=MyISAM; 
INSERT INTO pctable (parent_id) VALUES (0); 
INSERT INTO pctable (parent_id) SELECT parent_id+1 FROM pctable; 
INSERT INTO pctable (parent_id) SELECT parent_id+2 FROM pctable; 
INSERT INTO pctable (parent_id) SELECT parent_id+3 FROM pctable; 
INSERT INTO pctable (parent_id) SELECT parent_id+4 FROM pctable; 
INSERT INTO pctable (parent_id) SELECT parent_id+5 FROM pctable; 
SELECT * FROM pctable; 

這裏是查詢查看所有父母,祖先和家庭樹

SELECT 
    id,parent_id, 
    GetParentIDByID(id), 
    GetAncestry(id), 
    GetFamilyTree(id) 
FROM pctable; 

試試看!

+0

我得到一個錯誤_ERROR 1292(22007):截斷不正確的DOUBLE值:'4,5'_ getFamilyTree。任何建議,爲什麼它可能會發生!?感謝 – idok

+0

當使用LazyLoad時,您的GetAncestry函數基本上是JSTree搜索功能的完美解決方案。謝了哥們! – Broco