MySQL的先前等效连接

时间:2011-10-03 04:33:05

标签: mysql sql stored-procedures

所有

我在表中有三个字段,用于定义MySQL数据库版本5.0中存在的父子关系。表名是tb_Tree,它包含以下数据:

Table Name: tb_Tree

Id | ParentId | Name
--------------------
1  | 0        | Fruits
2  | 0        | Vegetables
3  | 1        | Apple
4  | 1        | Orange
5  | 2        | Cabbage
6  | 2        | Eggplant

如果指定了ParentId,如何编写查询以获取所有子节点。请注意,给出的表条目只是示例数据,它们可以包含更多行。 Oracle有一个“CONNECT BY PRIOR”子句,但我没有找到类似MySQL的东西。任何人都可以建议吗?

由于

6 个答案:

答案 0 :(得分:10)

MySQL不支持递归查询,所以你必须这么做:

  1. 选择ParentID = X其中X是您的根目录的行。
  2. 从(1)收集Id值。
  3. 对(2)中的每个Id重复(1)。
  4. 手动保持递归,直到找到所有叶节点。
  5. 如果你知道最大深度,那么你可以将你的表连接到自己(使用LEFT OUTER JOIN)到最大可能的深度,然后清理NULL。

    您还可以将树表示更改为nested sets

答案 1 :(得分:2)

您还可以查看这个有趣的博客,该博客演示了如何在mysql中获得类似的结果

http://explainextended.com/2009/03/17/hierarchical-queries-in-mysql/

答案 2 :(得分:2)

这是一个老线程,但由于我在另一个论坛得到了问题,我想我会在这里添加它。对于这种情况,我创建了一个硬编码的存储过程来处理特定情况。这当然有一些缺点,因为并非所有用户都可以随意创建存储过程,但仍然如此。

考虑下表中包含节点和子节点:

CREATE TABLE nodes (
       parent INT,
       child INT
);

INSERT INTO nodes VALUES
       ( 5,  2), ( 5, 3),
       (18, 11), (18, 7),
       (17,  9), (17, 8),
       (26, 13), (26, 1), (26,12),
       (15, 10), (15, 5),       
       (38, 15), (38, 17), (38, 6),
       (NULL, 38), (NULL, 26), (NULL, 18);

使用此表,以下存储过程将计算由提供的节点的所有后代组成的结果集:

delimiter $$
CREATE PROCEDURE find_parts(seed INT)
BEGIN
  -- Temporary storage
  DROP TABLE IF EXISTS _result;
  CREATE TEMPORARY TABLE _result (node INT PRIMARY KEY);

  -- Seeding
  INSERT INTO _result VALUES (seed);

  -- Iteration
  DROP TABLE IF EXISTS _tmp;
  CREATE TEMPORARY TABLE _tmp LIKE _result;
  REPEAT
    TRUNCATE TABLE _tmp;
    INSERT INTO _tmp SELECT child AS node
      FROM _result JOIN nodes ON node = parent;

    INSERT IGNORE INTO _result SELECT node FROM _tmp;
  UNTIL ROW_COUNT() = 0
  END REPEAT;
  DROP TABLE _tmp;
  SELECT * FROM _result;
END $$
delimiter ;

答案 3 :(得分:1)

以下targetCompatibility列出了所有植物及其if (strlen($a) > strlen($b)) return 1; elseif (strlen($a) < strlen($b)) return -1; else return 0; }; 最多4个级别(当然您可以扩展级别):

select

然后您可以使用此查询来获取最终结果。例如,你可以得到所有的孩子#34; Fruits&#34;由下面的sql:

parentid

答案 4 :(得分:1)

可能会迟到。

使用MySQL8,您可以使用递归子句实现它。这是示例。

 with recursive cte (id, name, parent_id) as (
  select     id,
             name,
             parent_id
  from       products
  where      parent_id = 19
  union all
  select     p.id,
             p.name,
             p.parent_id
  from       products p
  inner join cte
          on p.parent_id = cte.id
)
select * from cte;

要获得更多帮助,请找到另一个thread,希望它会帮助某人。

答案 5 :(得分:0)

下面的存储过程订购一个表,该表的行具有前一个的后引用。注意第一步我将行复制到临时表 - 这些行符合某些条件。在我的情况下,这些是属于相同线性的行(在GPS导航中使用的道路)。业务领域并不重要。就我而言,我正在排序属于同一条道路的细分

DROP PROCEDURE IF EXISTS orderLocations; DELIMITER //

CREATE PROCEDURE orderLocations(_full_linear_code VARCHAR(11))   BEGIN

DECLARE _code VARCHAR(11);
DECLARE _id INT(4);
DECLARE _count INT(4);
DECLARE _pos INT(4);

DROP TEMPORARY TABLE IF EXISTS temp_sort;

CREATE TEMPORARY TABLE temp_sort (
  id              INT(4) PRIMARY KEY,
  pos             INT(4),
  code            VARCHAR(11),
  prev_code       VARCHAR(11)
);

-- copy all records to sort into temp table - this way sorting would go all in memory
INSERT INTO temp_sort SELECT
                         id, -- this is primary key of original table
                         NULL, -- this is position that still to be calculated
                         full_tmc_code, -- this is a column that references sorted by
                         negative_offset -- this is a reference to the previous record (will be blank for the first)
                       FROM tmc_file_location
                       WHERE linear_full_tmc_code = _full_linear_code;

-- this is how many records we have to sort / update position
SELECT count(*)
FROM temp_sort
INTO _count;

-- first position index
SET _pos = 1;

-- pick first record that has no prior record
SELECT
  code,
  id
FROM temp_sort l
WHERE prev_code IS NULL
INTO _code, _id;

-- update position of the first record
UPDATE temp_sort
SET pos = _pos
WHERE id = _id;

-- all other go by chain link
WHILE (_pos < _count) DO
  SET _pos = _pos +1;

  SELECT
    code,
    id
  FROM temp_sort
  WHERE prev_code = _code
  INTO _code, _id;


  UPDATE temp_sort
  SET pos = _pos
  WHERE id = _id;

END WHILE;

-- join two tables and return position along with all other fields
SELECT
  t.pos,
  l.*
FROM tmc_file_location l, temp_sort t
WHERE t.id = l.id
ORDER BY t.pos;

END;