检索Adjacency-List-Model数据,不包括已定义节点的数组

时间:2012-12-22 12:57:39

标签: php sql recursion hierarchical-data

数据输入格式为:

+-----------+------------------+------+-----+---------+-------+
| Field     | Type             | Null | Key | Default | Extra |
+-----------+------------------+------+-----+---------+-------+
| parent_id | int(10) unsigned | NO   |     | NULL    |       |
| child_id  | int(10) unsigned | NO   |     | NULL    |       |
+-----------+------------------+------+-----+---------+-------+

此数据定义了使用DOT脚本绘制树形图的关系。 DOT足够复杂,可以处理每个节点之间链接的所有递归,例如

1 -> 2;
1 -> 3;
2 -> 4;
4 -> 5;
4 -> 6;
6 -> 7;

将生成:

enter image description here

我需要排除黑名单数组定义的分支,例如如果黑名单数组为[4],则DOT脚本需要变为:

1 -> 2;
1 -> 3;
2 -> 4;

2 个答案:

答案 0 :(得分:1)

如果您的DBMS支持递归查询,您可以通过递归查询(可以放入视图甚至函数)修剪树。此示例适用于Postgres,但可以适用于MS或Oracle。

DROP SCHEMA tmp CASCADE;
CREATE SCHEMA tmp ;
SET search_path=tmp;

CREATE TABLE family
        ( parent_id INTEGER NOT NULL
        , child_id INTEGER NOT NULL
        , PRIMARY KEY (parent_id,child_id)
        );

INSERT INTO family(parent_id,child_id) VALUES
 (1 , 2) ,(1 , 3)
,(2 , 4)
,(4 , 5) ,(4 , 6)
,(6 , 7)
        ;

CREATE TABLE black_sheep (id INTEGER NOT NULL PRIMARY KEY);
INSERT INTO black_sheep(id) VALUES(4);
-- INSERT INTO black_sheep(id) VALUES(6);

WITH RECURSIVE tree AS (
        SELECT parent_id AS opa
                , parent_id as dad
                , child_id AS kid
        FROM family f0
        WHERE NOT EXISTS (
                SELECT *
                FROM family nx
                WHERE nx.child_id = f0.parent_id
                )
        UNION ALL
        SELECT tr.opa AS opa
                , f1.parent_id AS dad
                , f1.child_id AS kid
        FROM family f1
        JOIN tree tr ON tr.kid = f1.parent_id
        WHERE NOT EXISTS (
                SELECT *
                FROM black_sheep nx
                WHERE nx. id = f1.parent_id
                )
        )
SELECT * FROM tree;

结果:

 opa | dad | kid 
-----+-----+-----
   1 |   1 |   2
   1 |   1 |   3
   1 |   2 |   4
(3 rows)

答案 1 :(得分:0)

这是我设法提出的最有效的方法。

$relations  = $db->query("SELECT `parent_id`, `child_id` FROM `relations` ORDER BY `parent_id` ASC LIMIT 500;")->fetchAll(PDO::FETCH_ASSOC);

function filterALMData ($data, array $exclude) {
    while (count($exclude)) {
        $new_exclude = [];
        foreach ($data as $i => $node) {
            if (in_array($node['parent_id'], $exclude)) {               
                $new_exclude[] = $node['child_id'];
                unset($data[$i]);
            }
        }
        $exclude = $new_exclude;
    }
    return $data;
};


$data = filterALMData($relations, [4]);

我发帖说明我到目前为止所尝试的内容。这不是一个好的答案。