As this has been brought up by @Pawan Sharma, I thought that I might give some answer as well.
All given solutions suffer from common problem - they perform SQL query for each and every child. E.g., if there are 100 childs in 2nd level, then 100 queries will be done, while it can actually be done in single query by using where parent_id in (<list_of_ids>)
.
Sample DB:
create table category (
id int auto_increment primary key,
parent_id int default null,
title tinytext,
foreign key (parent_id) references category (id)
) engine = InnoDB;
insert into category (id, parent_id, title) values
(1, null, '1'),
(2, null, '2'),
(3, null, '3'),
(4, 1 , '1.1'),
(5, 1 , '1.2'),
(6, 1 , '1.3'),
(7, 4 , '1.1.1'),
(8, 4 , '1.1.2'),
(9, 7 , '1.1.1.1');
Here's my solution:
/**
* @param null|int|array $parentID
*/
function getTree($parentID) {
$sql = "select id, parent_id, title from category where ";
if ( is_null($parentID) ) {
$sql .= "parent_id is null";
}
elseif ( is_array($parentID) ) {
$parentID = implode(',', $parentID);
$sql .= "parent_id in ({$parentID})";
}
else {
$sql .= "parent_id = {$parentID}";
}
$tree = array();
$idList = array();
$res = mysql_query($sql);
while ( $row = mysql_fetch_assoc($res) ) {
$row['children'] = array();
$tree[$row['id']] = $row;
$idList[] = $row['id'];
}
mysql_free_result($res);
if ( $idList ) {
$children = getTree($idList);
foreach ( $children as $child ) {
$tree[$child['parent_id']]['children'][] = $child;
}
}
return $tree;
}
With provided sample data, it does at most 5 queries, when called as getTree(null)
(for all entries):
select id, parent_id, title from category where parent_id is null
select id, parent_id, title from category where parent_id in (1,2,3)
select id, parent_id, title from category where parent_id in (4,5,6)
select id, parent_id, title from category where parent_id in (7,8)
select id, parent_id, title from category where parent_id in (9)
When called as getTree(4)
, 3 queries are performed:
select id, parent_id, title from category where parent_id = 4
select id, parent_id, title from category where parent_id in (7,8)
select id, parent_id, title from category where parent_id in (9)