I have a mysql table that represents a pseudo directory system:
CREATE TABLE `file_directories` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`parent_id` int(11) DEFAULT NULL,
`name` varchar(255) NOT NULL,
`level` int(11) NOT NULL DEFAULT '1',
`created` datetime NOT NULL,
PRIMARY KEY (`name`,`id`),
KEY `id` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=latin1
When a user is browsing this system our function receives a path that is made up of entries from the name
column.
So, something like first/child of first/grandchild
or second/child of second/grandchild
would be a valid path and would look like this in the database.
/----------------------------------------------------\
| id | parent_id | name | level | created |
|----|-----------|-----------------|-------|---------|
| 1 | NULL | First | 1 | ... |
| 2 | 1 | Child of First | 2 | ... |
| 3 | 2 | Grandchild | 3 | ... |
| 4 | NULL | Second | 1 | ... |
| 5 | 4 | Child of Second | 2 | ... |
| 6 | 5 | Grandchild | 3 | ... |
\----------------------------------------------------/
Now currently if I want to list a directories children my process is this:
$path = 'first/child of first'; // demo data
$path = explode('/', $path); //array('first', 'child of first');
$level = count($path);
$name = end($path);
//query is not actually built like this, it uses the Codeigniter Active Records library
//but this is effectively the end result,
$sql = "SELECT * FROM `file_directories` WHERE `name` = '$name' AND `level` = $level";
///etc
Which works fine, until we deal with the grandchild
directories, which have the same name and exist at the same level.
The directory structure enforces only one directory can exist with the same parent_id
and name
but same name
'd directories with different parent_id
's can exist on the same level
.
I cannot change what data I am passed, so the only way I can think of to do this is to start at the root node, and loop down doing multiple queries to find the correct child.
So, for the grandchild of second, the queries would be.
$parent_id = NULL;
foreach($path as $seg){
$id = SQL: SELECT `id` FROM `file_directories` WHERE `name` = '$seg' AND `parent_id` = (IS NULL for root node) $parent_id;
}
//Get the actual node
$node = SQL: SELECT `*` FROM `file_directories` WHERE `id` = '$id';
But, that's a lot of queries, so, without changing what data I am given, is there a better way of tracing through the tree? or selecting the correct node?
learn the about wonders of recursive functions: This code is bit simplified.
function select_child($node_id, $level, $target_level) {
if(SELECT new_node_id WHERE parent_id = $node_id)
if($level = $target_level) {
return($new_node);
} else {
$results->add(select_child($new_node_id, ($level +1), $target_level);
}
} else {
return(NULL);
}
}
this function loops through the children of the given node until it finds a "leaf" (node without child) or it reaches the targeted level. if you are working with trees, most of your functions have to be recursive (calling themself until a specified condition is matched).
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.