php - recursive - select recursivo mysql
php/Mysql mejor estructura de árbol (3)
Tengo que construir un árbol que contendrá alrededor de 300 nodos dentro de él. El árbol no tiene limitaciones de profundidad. Así que puede tener 3 o 15 niveles. Cada nodo puede tener un número ilimitado de hijos.
La prioridad es obtener un árbol / subárbol completo lo más rápido posible, pero también necesito agregar nodos o mover nodos a veces pero no tan a menudo.
Quiero saber la mejor manera de almacenar el árbol en la base de datos y la mejor manera de recuperar los datos, si es posible, en php.
Este es un gran artículo al respecto: mikehillyer.com/articles/managing-hierarchical-data-in-mysql . Utilicé durante mucho tiempo.
Si tiene alguna capacidad matemática, ¡realmente puede entender por qué es tan bueno!
Puede utilizar un modelo de conjunto anidado, ya que produce consultas muy eficientes. Consulte mikehillyer.com/articles/managing-hierarchical-data-in-mysql y lea la sección llamada Modelo de conjunto anidado .
Si está utilizando un ORM como Doctrine, incluye capacidades de conjuntos anidados .
Puede ser difícil para algunos comprender los conceptos de conjuntos anidados de izquierda y derecha. Descubrí que al usar esos números como una analogía para los números de línea de las etiquetas de apertura / cierre en un documento XML, a las personas les resulta más fácil de entender.
Por ejemplo, tome el ejemplo de datos del enlace de MySQL anterior:
+-------------+----------------------+-----+-----+
| category_id | name | lft | rgt |
+-------------+----------------------+-----+-----+
| 1 | ELECTRONICS | 1 | 20 |
| 2 | TELEVISIONS | 2 | 9 |
| 3 | TUBE | 3 | 4 |
| 4 | LCD | 5 | 6 |
| 5 | PLASMA | 7 | 8 |
| 6 | PORTABLE ELECTRONICS | 10 | 19 |
| 7 | MP3 PLAYERS | 11 | 14 |
| 8 | FLASH | 12 | 13 |
| 9 | CD PLAYERS | 15 | 16 |
| 10 | 2 WAY RADIOS | 17 | 18 |
+-------------+----------------------+-----+-----+
Si toma los campos lft , rgt y los usa como números de línea para un documento XML, obtendrá:
1. <electronics>
2. <televisions>
3. <tube>
4. </tube>
5. <lcd>
6. </lcd>
7. <plasma>
8. </plasma>
9. </televisions>
10. <portable electronics>
11. <mp3 players>
12. <flash>
13. </flash>
14. </mp3 players>
15. <cd players>
16. </cd players>
17. <2 way radios>
18. </2 way radios>
19. </portable electronics>
20. </electronics>
Verlo de esta manera puede hacer que sea mucho más fácil para algunos visualizar la jerarquía de conjuntos anidados resultante. También aclara por qué este enfoque mejora la eficiencia ya que permite seleccionar nodos completos sin la necesidad de múltiples consultas o uniones.
<?php
$host = "localhost";
//Database user name.
$login = "root";
//Database Password.
$dbpass = "";
$dbname = "abc";
$PDO = new PDO("mysql:host=localhost;dbname=$dbname", "$login", "$dbpass");
$rows = array();
$sql = ''SELECT id, parent_id, name FROM employee'';
$query = $PDO->prepare($sql);
$query->execute();
$rows = array();
if (!$query)
{
$error = ''Error fetching page structure, for nav menu generation.'';
exit();
}
while($row = $query->fetch(PDO::FETCH_ASSOC)){
if( strcasecmp($row[''parent_id''],''null'') === 0 || empty($row[''parent_id'']) ) {
$row[''parent_id''] = null;
}
$rows[] = $row;
}
// covert raw result set to tree
$menu = convertAdjacencyListToTree(null,$rows,''id'',''parent_id'',''links'');
// echo ''<pre>'',print_r($menu),''</pre>'';
// display menu
echo themeMenu($menu,1);
/*
* ------------------------------------------------------------------------------------
* Utility functions
* ------------------------------------------------------------------------------------
*/
/*
* Convert adjacency list to hierarchical tree
*
* @param value of root level parent most likely null or 0
* @param array result
* @param str name of primary key column
* @param str name of parent_id column - most likely parent_id
* @param str name of index that children will reside ie. children, etc
* @return array tree
*/
function convertAdjacencyListToTree($intParentId,&$arrRows,$strIdField,$strParentsIdField,$strNameResolution) {
$arrChildren = array();
for($i=0;$i<count($arrRows);$i++) {
if($intParentId === $arrRows[$i][$strParentsIdField]) {
$arrChildren = array_merge($arrChildren,array_splice($arrRows,$i--,1));
}
}
$intChildren = count($arrChildren);
if($intChildren != 0) {
for($i=0;$i<$intChildren;$i++) {
$arrChildren[$i][$strNameResolution] = convertAdjacencyListToTree($arrChildren[$i][$strIdField],$arrRows,$strIdField,$strParentsIdField,$strNameResolution);
}
}
return $arrChildren;
}
/*
* Theme menu
*
* @param array menu
* @param runner (depth)
* @return str themed menu
*/
function themeMenu($menu,$runner) {
$out = '''';
if(empty($menu)) {
return $out;
}
$out.=''<ul>'';
foreach($menu as $link) {
$out.= sprintf(
''<li class="depth-%u">%s%s</li>''
,$runner
,$link[''name'']
,themeMenu($link[''links''],($runner+1))
);
}
$out.=''</ul>'';
return $out;
}
?>