Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/php/248.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Php 将分层数据从数据库加载到数组中_Php_Arrays_Database_Hierarchical Data - Fatal编程技术网

Php 将分层数据从数据库加载到数组中

Php 将分层数据从数据库加载到数组中,php,arrays,database,hierarchical-data,Php,Arrays,Database,Hierarchical Data,我在数据库中有一个具有以下结构/数据的表: n_id n_parent_id ... some other fields ... ==== =========== ========================= 1 null ... 2 null ... ... 11 1 ... 12 1

我在数据库中有一个具有以下结构/数据的表:

n_id      n_parent_id      ... some other fields ...
====      ===========      =========================
 1         null            ...
 2         null            ...
...
11            1            ...
12            1            ...
...
25            2            ...
...
65           11            ...
66           11            ...
...
从上面的示例可以看出,此表存储分层数据。我需要将其加载到类似于fasion的树中的PHP数组中,以便该数组包含如下内容:

Array
(
    [1] => Array
        (
            [n_id] => 1
            [n_parent_id] => 
            [other_data] => ...
            [children] => Array
                (
                    [11] => Array
                        (
                            [n_id] => 11
                            [n_parent_id] => 1
                            [other_data] => ...
                            [children] => Array
                                 (
                                    [65] => Array
                                        (
                                            [n_id] => 65
                                            [n_parent_id] => 11
                                            [other_data] => ...
                                        )
                                 )
   ... and so on ...
)
我可以轻松处理一个级别:

//ordering will ensure that parent row is always read before children rows
//my data is set up in this way.
$query = "select n_id, n_parent_id, other_data from hierarchy_table order by n_parent_id, n_id";
if(($dbs = $dbh->query($query)) === FALSE) {
    $e = $dbh->errorInfo();
    // ... deal with error
}
$result = array();
while($row = $dbs->fetch(PDO::FETCH_ASSOC)) {
    if(is_null($row['n_parent_id'])) {
        $result[$row['n_id']] = array(
            'n_id' => $row['n_id'],
            'n_parent_id' => null,
            'other_data' => ...,
            'children' => array()
        );
    }
    elseif(isset($result[$row['n_parent_id']])) {
        $result[$row['n_parent_id']]['children'][$row['n_id']] = array(
            'n_id' => $row['n_id'],
            'n_parent_id' => $row['n_parent_id'],
            'other_data' => ...
            children => array()
        );
    }
}
然而,我似乎无法将其扩展到多个级别,而不必在每次需要添加行时递归地循环整个数组。当然,如果是Java或C,我只会存储指向数据结构的指针,这将解决问题,但在PHP中,这并不是那么容易。最后,我需要将其
json\u encode
发送到客户端

介绍了一个类似的问题,但我在数据库中没有实际的层次结构信息-只有父id

在此方面的任何帮助都将不胜感激


编辑:我的数据库表包含数十万行,因此性能很重要。

经过一番努力,我通过使用引用对记录集进行一次遍历(仅读取每条记录一次)来获得所需的内容。由于PHP中对内存引用的支持相当有限,因此需要一些有趣的东西来保持thin正常工作(例如,我从DB中读取的每一行都有一个新的变量名)。不管怎样,下面是我最后得到的代码(此代码只处理
id
parent\u id
——但读取/存储更多数据很简单):

对该数据执行时:

mysql> select * from test_table;
+------+-------------+
| n_id | n_parent_id |
+------+-------------+
|    1 |        NULL |
|    2 |        NULL |
|    3 |           1 |
|    4 |           1 |
|    5 |           2 |
|    6 |           2 |
|    7 |           5 |
|    8 |           5 |
+------+-------------+
最后一次
print\r
生成此输出:

Array
(
    [1] => Array
        (
            [n_id] => 1
            [n_parent_id] => 
            [children] => Array
                (
                    [3] => Array
                        (
                            [n_id] => 3
                            [n_parent_id] => 1
                            [children] => Array
                                (
                                )

                        )

                    [4] => Array
                        (
                            [n_id] => 4
                            [n_parent_id] => 1
                            [children] => Array
                                (
                                )

                        )

                )

        )

    [2] => Array
        (
            [n_id] => 2
            [n_parent_id] => 
            [children] => Array
                (
                    [5] => Array
                        (
                            [n_id] => 5
                            [n_parent_id] => 2
                            [children] => Array
                                (
                                    [7] => Array
                                        (
                                            [n_id] => 7
                                            [n_parent_id] => 5
                                            [children] => Array
                                                (
                                                )

                                        )

                                    [8] => Array
                                        (
                                            [n_id] => 8
                                            [n_parent_id] => 5
                                            [children] => Array
                                                (
                                                )

                                        )

                                )

                        )

                    [6] => Array
                        (
                            [n_id] => 6
                            [n_parent_id] => 2
                            [children] => Array
                                (
                                )

                        )

                )

        )

)

这正是我所寻找的。

因为我也面临着几乎相同的问题,而Aleks G的创造性(!)解决方案并没有完全满足我的需要,因为我用嵌套集模型保存层次数据,这是我处理嵌套集时的解决方案(这需要一段时间才能实现)。
$data
数组必须根据前序遍历进行排序

用法示例:

$data =
[
    0 => ['ID' => 0, 'depth' => 0],
    1 => ['ID' => 1, 'depth' => 1],
    2 => ['ID' => 2, 'depth' => 2],
    3 => ['ID' => 6, 'depth' => 2],
    4 => ['ID' => 10, 'depth' => 1]
];

$IDs = hierachicDataToArray($data);
print_r($IDs);

$IDs = hierachicDataToArray($data, true);
print_r($IDs);
输出:

Array
(
    [0] => Array
        (
            [1] => Array
                (
                    [2] => 2
                    [6] => 6
                )

            [10] => 10
        )

)

Array
(
    [0] => Array
        (
            [ID] => 0
            [depth] => 0
            [children] => Array
                (
                    [1] => Array
                        (
                            [ID] => 1
                            [depth] => 1
                            [children] => Array
                                (
                                    [2] => Array
                                        (
                                            [ID] => 2
                                            [depth] => 2
                                            [children] => Array
                                                (
                                                )

                                        )

                                    [6] => Array
                                        (
                                            [ID] => 6
                                            [depth] => 2
                                            [children] => Array
                                                (
                                                )

                                        )

                                )

                        )

                    [10] => Array
                        (
                            [ID] => 10
                            [depth] => 1
                            [children] => Array
                                (
                                )

                        )

                )

        )

)
方法:

/**
 * Convert hierarchic data records to a multidimensional array.
 * Expects an array in the form: [<i> => ['ID' => <int ID>, 'depth' => <int depth>, '<string>' => <mixed>, ...]]
 * At least the 'ID' and 'depth' key/value pairs must exist.
 * @author: lsblsb[at]gmx.de
 * @copyright: GPL-3.0
 * 
 * @param array $data The data array.
 * @param bool $incData = false Whether to include additional data or not.
 * @param bool $IDKeys = true Whether to use IDs as key or not (false only possible when $incData = true)
 * 
 * @return array[]
 */
function hierarchicDataToArray(array $data, $incData = false, $IDKeys = true)
{
    $nodes = [];

    foreach($data as $i => $record)
    {
        $ID = $record['ID'];
        $depth = $record['depth'];
        $prevRecord = isset($data[$i-1]) ? $data[$i-1] : false;
        $prevDepth = $prevRecord ? $prevRecord['depth'] : false;
        $prevID = $prevRecord ? $prevRecord['ID'] : false;
        $nextRecord = isset($data[$i+1]) ? $data[$i+1] : false;
        $nextDepth = $nextRecord ? $nextRecord['depth'] : false;
        $nextID = $nextRecord ? $nextRecord['ID'] : false;

        if($prevRecord && $prevDepth >= $depth)
        {
            $pID = $depthIDs[$depth-1];
            if($depth == 1)
            {
                if($incData)
                    $nodes[$pID]['children'][$ID] = &$refs[$ID];
                else
                    $nodes[$pID][$ID] = &$refs[$ID];
            }
            else
            {
                if($incData)
                    $refs[$pID]['children'][$ID] = &$refs[$ID];
                else
                    $refs[$pID][$ID] = &$refs[$ID];
            }
        }

        if($nextRecord && $nextDepth > $depth)
        {
            if($depth == 0)
            {
                if($incData)
                {
                    if(!isset($nodes[$ID])) $nodes[$ID] = $record;
                    $nodes[$ID]['children'][$nextID] = &$refs[$nextID];
                }
                else
                    $nodes[$ID][$nextID] = &$refs[$nextID];
            }
            else
            {
                if($incData)
                {
                    if(!isset($refs[$ID])) $refs[$ID] = $record;
                    $refs[$ID]['children'][$nextID] = &$refs[$nextID];
                }
                else
                    $refs[$ID][$nextID] = &$refs[$nextID];
            }
        }
        else
        {
            $node = $incData ? $record + ['children' => []] : $ID;
            $refs[$ID] = $node;
        }

        if(!$IDKeys && $incData)
        {
            if(!$nextRecord)
            {
                $nodes = array_values($nodes);
                $nodes[0]['children'] = array_values($nodes[0]['children']);
            }
            elseif($nextDepth < $depth)
            {
                $pID = $depthIDs[$depth-1];
                $refs[$pID]['children'] = array_values($refs[$pID]['children']);
            }
        }

        $depthIDs[$depth] = $ID;
    }

    return $nodes;
}
/**
*将层次数据记录转换为多维数组。
*需要以下格式的数组:[=>['ID'=>,'depth'=>,''=>,…]]
*至少必须存在“ID”和“深度”键/值对。
*@author:lsblsb[at]gmx.de
*@版权所有:GPL-3.0
* 
*@param array$data数据数组。
*@param bool$incData=false是否包含其他数据。
*@param bool$IDKeys=true是否将ID用作密钥(仅当$incData=true时可能为false)
* 
*@return数组[]
*/
函数层次结构CDATA阵列(数组$data、$incData=false、$IDKeys=true)
{
$nodes=[];
foreach($i=>$record形式的数据)
{
$ID=$record['ID'];
$depth=$record['depth'];
$prevRecord=isset($data[$i-1])?$data[$i-1]:false;
$prevDepth=$prevRecord?$prevRecord['depth']:false;
$prevID=$prevRecord?$prevRecord['ID']:false;
$nextRecord=isset($data[$i+1])?$data[$i+1]:false;
$nextDepth=$nextRecord?$nextRecord['depth']:false;
$nextID=$nextRecord?$nextRecord['ID']:false;
如果($prevRecord&&$prevDepth>=$depth)
{
$pID=$depthIDs[$depth-1];
如果($depth==1)
{
如果($incData)
$nodes[$pID]['children'][$ID]=&$refs[$ID];
其他的
$nodes[$pID][$ID]=&$refs[$ID];
}
其他的
{
如果($incData)
$refs[$pID]['children'][$ID]=&$refs[$ID];
其他的
$refs[$pID][$ID]=&$refs[$ID];
}
}
如果($nextRecord&&$nextDepth>$depth)
{
如果($depth==0)
{
如果($incData)
{
如果(!isset($nodes[$ID]))$nodes[$ID]=$record;
$nodes[$ID]['children'][$nextID]=&$refs[$nextID];
}
其他的
$nodes[$ID][$nextID]=&$refs[$nextID];
}
其他的
{
如果($incData)
{
如果(!isset($refs[$ID]))$refs[$ID]=$record;
$refs[$ID]['children'][$nextID]=&$refs[$nextID];
}
其他的
$refs[$ID][$nextID]=&$refs[$nextID];
}
}
其他的
{
$node=$incData?$record+['children'=>[]]:$ID;
$refs[$ID]=$node;
}
如果(!$IDKeys&&$incData)
{
如果(!$nextRecord)
{
$nodes=数组_值($nodes);
$nodes[0]['children']=数组_值($nodes[0]['children']);
}
elseif($nextDepth<$depth)
{
$pID=$depthIDs[$depth-1];
$refs[$pID]['children']=数组_值($refs[$pID]['children']);
}
}
$depthIDs[$depth]=$ID;
}
返回$nodes;
}

@bpositive的可能副本请勿进行无意义/无用的编辑-这些编辑没有帮助,将被还原。@deceze感谢您的指针。链接问题确实提供了一种解决方案,但是在我的例子中,数据库表可能包含数十万条记录,因此您在该答案中提供的功能将非常低效。。。当然,在整个阵列上多次扫描/循环是一种选择,但如果可能的话,我想避免。这很公平,但这会使问题变得更难(正如你已经知道的)。@deceze是的,我知道。。。PHP不是速度优化的最佳语言。。。
/**
 * Convert hierarchic data records to a multidimensional array.
 * Expects an array in the form: [<i> => ['ID' => <int ID>, 'depth' => <int depth>, '<string>' => <mixed>, ...]]
 * At least the 'ID' and 'depth' key/value pairs must exist.
 * @author: lsblsb[at]gmx.de
 * @copyright: GPL-3.0
 * 
 * @param array $data The data array.
 * @param bool $incData = false Whether to include additional data or not.
 * @param bool $IDKeys = true Whether to use IDs as key or not (false only possible when $incData = true)
 * 
 * @return array[]
 */
function hierarchicDataToArray(array $data, $incData = false, $IDKeys = true)
{
    $nodes = [];

    foreach($data as $i => $record)
    {
        $ID = $record['ID'];
        $depth = $record['depth'];
        $prevRecord = isset($data[$i-1]) ? $data[$i-1] : false;
        $prevDepth = $prevRecord ? $prevRecord['depth'] : false;
        $prevID = $prevRecord ? $prevRecord['ID'] : false;
        $nextRecord = isset($data[$i+1]) ? $data[$i+1] : false;
        $nextDepth = $nextRecord ? $nextRecord['depth'] : false;
        $nextID = $nextRecord ? $nextRecord['ID'] : false;

        if($prevRecord && $prevDepth >= $depth)
        {
            $pID = $depthIDs[$depth-1];
            if($depth == 1)
            {
                if($incData)
                    $nodes[$pID]['children'][$ID] = &$refs[$ID];
                else
                    $nodes[$pID][$ID] = &$refs[$ID];
            }
            else
            {
                if($incData)
                    $refs[$pID]['children'][$ID] = &$refs[$ID];
                else
                    $refs[$pID][$ID] = &$refs[$ID];
            }
        }

        if($nextRecord && $nextDepth > $depth)
        {
            if($depth == 0)
            {
                if($incData)
                {
                    if(!isset($nodes[$ID])) $nodes[$ID] = $record;
                    $nodes[$ID]['children'][$nextID] = &$refs[$nextID];
                }
                else
                    $nodes[$ID][$nextID] = &$refs[$nextID];
            }
            else
            {
                if($incData)
                {
                    if(!isset($refs[$ID])) $refs[$ID] = $record;
                    $refs[$ID]['children'][$nextID] = &$refs[$nextID];
                }
                else
                    $refs[$ID][$nextID] = &$refs[$nextID];
            }
        }
        else
        {
            $node = $incData ? $record + ['children' => []] : $ID;
            $refs[$ID] = $node;
        }

        if(!$IDKeys && $incData)
        {
            if(!$nextRecord)
            {
                $nodes = array_values($nodes);
                $nodes[0]['children'] = array_values($nodes[0]['children']);
            }
            elseif($nextDepth < $depth)
            {
                $pID = $depthIDs[$depth-1];
                $refs[$pID]['children'] = array_values($refs[$pID]['children']);
            }
        }

        $depthIDs[$depth] = $ID;
    }

    return $nodes;
}