Get all child, grandchild etc nodes under parent using php with mysql query results
Edit:
I had previously posted a solution to build a multi-dimensional array out of the output you gave as well as a way to get all child elements of a particular id
out of that particular array. I have now figured out how to retrieve the child elements straight from your output (without having to first go through a buildtree()
function:
function fetch_recursive($src_arr, $currentid, $parentfound = false, $cats = array())
{
foreach($src_arr as $row)
{
if((!$parentfound && $row['id'] == $currentid) || $row['parent_id'] == $currentid)
{
$rowdata = array();
foreach($row as $k => $v)
$rowdata[$k] = $v;
$cats[] = $rowdata;
if($row['parent_id'] == $currentid)
$cats = array_merge($cats, fetch_recursive($src_arr, $row['id'], true));
}
}
return $cats;
}
To use the function above, simply pass in the output array $data
to the first argument and the id
you want to retrieve the child elements from in the second argument:
ex.:
$list = fetch_recursive($data, 3);
Which should give you the correct array structure for id
3
(as seen in the example in the last codebox to this answer).
Original Answer:
I had never got around to writing a recursive function to build nested trees out of this design until now. I'm sure there are plenty of others who have written similar functions, but this one should definitely work for you:
function buildtree($src_arr, $parent_id = 0, $tree = array())
{
foreach($src_arr as $idx => $row)
{
if($row['parent_id'] == $parent_id)
{
foreach($row as $k => $v)
$tree[$row['id']][$k] = $v;
unset($src_arr[$idx]);
$tree[$row['id']]['children'] = buildtree($src_arr, $row['id']);
}
}
ksort($tree);
return $tree;
}
This function will recursively build a tree out of an adjacency list and keep the id's ordered in ascending order. This also makes the id
's of each parent/child the key of each array of information.
This code:
$r = mysql_query("SELECT * FROM test ");
$data = array();
while($row = mysql_fetch_assoc($r)) {
$data[] = $row;
}
echo '<pre>';
print_r(buildtree($data));
echo '</pre>';
Will output something like this:
Array
(
[1] => Array
(
[id] => 1
[name] => Electronics
[parent_id] => 0
[children] => Array
(
[2] => Array
(
[id] => 2
[name] => Televisions
[parent_id] => 1
[children] => Array
(
[4] => Array
(
[id] => 4
[name] => Tube
[parent_id] => 2
[children] => Array()
)
[5] => Array
(
[id] => 5
[name] => LCD
[parent_id] => 2
[children] => Array()
)
[6] => Array
(
[id] => 6
[name] => Plasma
[parent_id] => 2
[children] => Array()
)
)
)
[3] => Array
(
[id] => 3
[name] => Portable Electronics
[parent_id] => 1
[children] => Array
(
[7] => Array
(
[id] => 7
[name] => Mp3 Players
[parent_id] => 3
[children] => Array
(
[10] => Array
(
[id] => 10
[name] => Flash
[parent_id] => 7
[children] => Array()
)
)
)
[8] => Array
(
[id] => 8
[name] => CD Players
[parent_id] => 3
[children] => Array()
)
[9] => Array
(
[id] => 9
[name] => 2 Way Radios
[parent_id] => 3
[children] => Array()
)
)
)
)
)
)
To get all child-nodes of a particular id
onto a one-dimensional array, you can use this function:
function fetch_recursive($tree, $parent_id, $parentfound = false, $list = array())
{
foreach($tree as $k => $v)
{
if($parentfound || $k == $parent_id)
{
$rowdata = array();
foreach($v as $field => $value)
if($field != 'children')
$rowdata[$field] = $value;
$list[] = $rowdata;
if($v['children'])
$list = array_merge($list, fetch_recursive($v['children'], $parent_id, true));
}
elseif($v['children'])
$list = array_merge($list, fetch_recursive($v['children'], $parent_id));
}
return $list;
}
Based on the buildtree()
function above, let's say we wanted to get all child nodes of id
3:
echo '<pre>';
print_r(fetch_recursive(buildtree($a), 3));
echo '</pre>';
This will output:
Array
(
[0] => Array
(
[id] => 3
[name] => Portable Electronics
[parent_id] => 1
)
[1] => Array
(
[id] => 7
[name] => Mp3 Players
[parent_id] => 3
)
[2] => Array
(
[id] => 10
[name] => Flash
[parent_id] => 7
)
[3] => Array
(
[id] => 8
[name] => CD Players
[parent_id] => 3
)
[4] => Array
(
[id] => 9
[name] => 2 Way Radios
[parent_id] => 3
)
)
PHP and MySQL find all children and grandchildren of parents in database
Use the following code to get the data :
function getChildren($parent) {
$query = "SELECT * FROM tableName WHERE parent_id = $parent";
$result = mysql_query($query);
$children = array();
$i = 0;
while($row = mysql_fetch_assoc($result)) {
$children[$i] = array();
$children[$i]['name'] = $row['name'];
$children[$i]['children'] = getChildren($row['id']);
$i++;
}
return $children;
}
Call this function using
$finalResult = getChildren('*');
EDIT by James
Just to finish this answer, to print out the results into the list:
<?php
function printList($array = null) {
if (count($array)) {
echo "<ul>";
foreach ($array as $item) {
echo "<li>";
echo $item['name'];
if (count($item['children'])) {
printList($item['children']);
}
echo "</li>";
}
echo "</ul>";
}
}
printList($finalResult);
?>
PHP mysql Tree Child count and List All Child node level wise
It sounds like you just want a way of counting nested sets, I can reproduce your example without using a database with this code:
function returnResults($parent)
{
switch ($parent) {
case 'root':
return ['vijay', 'suresh', 'mukesh'];
case 'vijay':
return ['manish', 'rohan', 'manu'];
case 'manish':
return ['rinku', 'raja', 'vijay2'];
default:
return [];
}
}
function childCountLevelWise($parent, $level, &$result)
{
$result[$level] = empty($result[$level]) ? [] : $result[$level]; // init array
if ($level > 14) {
return; // ignore levels over 14
}
$levelResults = returnResults($parent); // get results for this parent
$result[$level] = array_merge($result[$level], $levelResults); // add to results for this level
foreach ($levelResults as $child) {
childCountLevelWise($child, $level + 1, $result); // check for each child at this level
}
}
And calling it and printing the results with this code
childCountLevelWise('root', 0, $result);
// print result
foreach ($result as $level => $people) {
if (!empty($people)) {
printf('Result for level %d: %s', $level, implode(',', $people));
echo "\n";
}
}
Will result in:
Result for level 0: vijay,suresh,mukesh
Result for level 1: manish,rohan,manu
Result for level 2: rinku,raja,vijay2
From there I think it should be simple enough to modify the returnResults
function in my example to query the database, although if you're using this on a lot of results you might want to consider the performance costs of this. There are good solutions to having tree structures in the database already, such as the Nested Set in Doctrine.
Create multiple categories with parent, child and grandchild
Finally i found good answer
ref : Parent child mysql
select t0.*,
concat(
case coalesce(t4.parent_id, 0)
when 0 then ''
else concat(cast(t4.parent_id as char), '\\')
end,
case coalesce(t3.parent_id, 0)
when 0 then ''
else concat(cast(t3.parent_id as char), '\\')
end,
case coalesce(t2.parent_id, 0)
when 0 then ''
else concat(cast(t2.parent_id as char), '\\')
end,
case coalesce(t1.parent_id, 0)
when 0 then ''
else concat(cast(t1.parent_id as char), '\\')
end,
case coalesce(t0.parent_id, 0)
when 0 then ''
else concat(cast(t0.parent_id as char), '\\')
end,
cast(t0.id as char)
) as path
from mytable t0
left join mytable t1 on t0.parent_id = t1.Id
left join mytable t2 on t1.parent_id = t2.Id
left join mytable t3 on t2.parent_id = t3.Id
left join mytable t4 on t3.parent_id = t4.Id
order by
concat(
case coalesce(t4.parent_id, 0)
when 0 then ''
else concat(cast(t4.parent_id as char), '\\')
end,
case coalesce(t3.parent_id, 0)
when 0 then ''
else concat(cast(t3.parent_id as char), '\\')
end,
case coalesce(t2.parent_id, 0)
when 0 then ''
else concat(cast(t2.parent_id as char), '\\')
end,
case coalesce(t1.parent_id, 0)
when 0 then ''
else concat(cast(t1.parent_id as char), '\\')
end,
case coalesce(t0.parent_id, 0)
when 0 then ''
else concat(cast(t0.parent_id as char), '\\')
end,
cast(t0.id as char)
)
How to get only the first level of depth child nodes?
Here's a solution:
select p1.* from tree_path as p1
left outer join (tree_path as p2 join tree_path as p3 on p2.children = p3.parent)
on p2.parent = p1.parent
and p3.children = p1.children
and p2.parent <> p2.children
and p3.parent <> p3.children
where p1.parent = 3 and p2.parent is NULL;
+----------+--------+
| children | parent |
+----------+--------+
| 3 | 3 |
| 7 | 3 |
| 8 | 3 |
+----------+--------+
Change the p1.parent=7 and you get this output:
+----------+--------+
| children | parent |
+----------+--------+
| 7 | 7 |
| 15 | 7 |
| 16 | 7 |
+----------+--------+
Here's the way it works: immediate children are descendants where there is a path from parent to child, but there is no path from parent through a third node to the child. So we try to join to such a path (p2->p3) and if none is found, then all columns of p2 and p3 will be NULL.
Related Topics
Loop Code for Each File in a Directory
How to Specify Composer Install Path
How to Create Installer for Website. PHP MySQL
PHP APIs for Hotmail, Gmail and Yahoo
Using Usort in PHP with a Class Private Function
How to Pass Arguments to My Function Through Add_Action
Proper Url Forming with a Query String and an Anchor Hashtag
Sqlstate[Hy000] [1698] Access Denied for User 'Root'@'Localhost'
How to Store an Array into MySQL
How to Check an Ip Address Is Within a Range of Two Ips in PHP
PHP Using Preg_Replace:"Delimiter Must Not Be Alphanumeric or Backslash" Error
Test If Port Open and Forwarded Using PHP
How to Get the Newest File in a Directory in PHP