使用递归PHP组织mySQL数据
我正在为一位客户创建一份调查问卷,要求将问题分为3个层次。我已经成功地创建了U.I。然而,在过去的3个小时里,我一直在尝试从数据库中提取数据,以确保所有数据都加载到正确的位置。数据库是由客户组织的,因此我无法控制它:使用递归PHP组织mySQL数据,php,mysql,recursion,if-statement,adjacency-list,Php,Mysql,Recursion,If Statement,Adjacency List,我正在为一位客户创建一份调查问卷,要求将问题分为3个层次。我已经成功地创建了U.I。然而,在过去的3个小时里,我一直在尝试从数据库中提取数据,以确保所有数据都加载到正确的位置。数据库是由客户组织的,因此我无法控制它: id description parentId about 1 Level 1 0 This is the top level or in my case tab1 2 Level 2 0
id description parentId about
1 Level 1 0 This is the top level or in my case tab1
2 Level 2 0 This is the next tab in the top level
3 Level 1a 1 This is the first category under tab1
4 Level 1b 1 This is the next category under tab1
5 Level 1a1 3 This is the content under the first category of tab1
因此,parentId为0的任何内容都是顶级内容,并且将包含parentId为1的第二级内容,依此类推。令人困惑的是,我几乎无法理解这一点,但这就是我被告知要这样做的方式
什么方法是执行此类操作的最佳方法?下面是我用作参考的另一个问题的示例(尽管不起作用)
任何帮助都将不胜感激。干杯如果您正好有3个级别,那么您可以尝试以下方法:
我在selects中添加了一个
lvl
字段,每个级别都有不同的值。还添加了o1、o2、o3,以便很好地排序嵌套级别,当然您可能还有其他需要。您可以在PHP中处理所有行,例如,将它们拆分为3个数组(每个级别一个数组),或者根据id创建一个查找表,等等。如果您正好有3个级别,那么您可以尝试以下方法:
我在selects中添加了一个
lvl
字段,每个级别都有不同的值。还添加了o1、o2、o3,以便很好地排序嵌套级别,当然您可能还有其他需要。您可以在PHP中处理所有行,例如将它们拆分为3个数组(每个级别一个数组),或者根据id创建一个查找表,等等。我也遇到了类似的问题,但经过大量的Google搜索和StackOverflow:-)
我找到了我的答案。。。。
这是我的编码方式
function showComments($parent = 0)
{
$commentQuery = "SELECT * FROM comment WHERE parent = ".mysql_real_escape_string($parentId);
$commentResult = mysql_query($commentQuery)
while ($row = mysql_fetch_array($commentResult))
{
echo '[Table containing comment data]';
showComments($row['commentID']);
}
}
showComments();
我也有同样的问题,但在谷歌搜索和堆垛泛滥之后:-) 我找到了我的答案。。。。 这是我的编码方式
function showComments($parent = 0)
{
$commentQuery = "SELECT * FROM comment WHERE parent = ".mysql_real_escape_string($parentId);
$commentResult = mysql_query($commentQuery)
while ($row = mysql_fetch_array($commentResult))
{
echo '[Table containing comment data]';
showComments($row['commentID']);
}
}
showComments();
如果您使用的是外部数据库,那么在PHP中这样做可能是值得的,而不是SQL。我还没有对以下内容进行基准测试,所以请尝试使用您的数据,看看性能是否有问题 您可以自己选择如何处理孤立记录(这些记录引用了不再存在的ParentID) 像这样在PHP中排序需要事先准备好所有数据,因此请使用类似PDO的
fetchAll(PDO::FETCH_ASSOC)
方法,其结果如下:
$data_from_database = array(
array("id" => 1, "parentId" => 0, "description" => "Level 1"),
array("id" => 2, "parentId" => 1, "description" => "Level 1a"),
array("id" => 3, "parentId" => 1, "description" => "Level 1b"),
array("id" => 4, "parentId" => 0, "description" => "Level 2"),
array("id" => 5, "parentId" => 2, "description" => "Level 1a1"),
array("id" => 6, "parentId" => 5, "description" => "Level 1a11a"),
array("id" => 7, "parentId" => 5, "description" => "Level 1a11b"),
array("id" => 8, "parentId" => 9, "description" => "Level 3"),
);
$data_from_database = array(
1 => array("id" => 1, "parentId" => 0, "description" => "Level 1",
"children" => array(), "is_orphan" => false),
...
);
首先,您需要将主键(ID)作为数组的键。下面还将键“children”和“is_orphan”添加到每个记录中
$data_by_id = array();
foreach($data_from_database as $row)
$data_by_id[$row["id"]] = $row + array(
"children" => array(),
"is_orphan" => false
);
这将看起来像这样:
$data_from_database = array(
array("id" => 1, "parentId" => 0, "description" => "Level 1"),
array("id" => 2, "parentId" => 1, "description" => "Level 1a"),
array("id" => 3, "parentId" => 1, "description" => "Level 1b"),
array("id" => 4, "parentId" => 0, "description" => "Level 2"),
array("id" => 5, "parentId" => 2, "description" => "Level 1a1"),
array("id" => 6, "parentId" => 5, "description" => "Level 1a11a"),
array("id" => 7, "parentId" => 5, "description" => "Level 1a11b"),
array("id" => 8, "parentId" => 9, "description" => "Level 3"),
);
$data_from_database = array(
1 => array("id" => 1, "parentId" => 0, "description" => "Level 1",
"children" => array(), "is_orphan" => false),
...
);
现在,它变得很棘手:我们将在数组中循环并添加引用
foreach($data_by_id as &$row)
{
if($row["parentId"] > 0)
{
if(isset($data_by_id[$row["parentId"]]))
$data_by_id[$row["parentId"]]["children"][] = &$row;
else
$row["is_orphan"] = true;
}
}
unset($row); // Clear reference (important).
最后一步是清理数组的“根”。它将包含对重复行的引用
foreach($data_by_id as $id => $row)
{
// If you use this option, you'll remove
// orphaned records.
#if($row["parentId"] > 0)
# unset($data_by_id[$id]);
// Use this to keep orphans:
if($row["parentId"] > 0 AND !$row["is_orphan"])
unset($data_by_id[$id]);
}
在每个步骤后使用print\r($data\u by\u id)
查看发生了什么
如果这证明是一个耗时的操作,请尝试仅通过执行
选择id,parentId FROM…
然后稍后获取元数据(如说明
)来构建树。您还可以将结果存储在Memcache中或序列化到数据库中 如果您使用的是外部数据库,那么在PHP中这样做可能是值得的,而不是SQL。我还没有对以下内容进行基准测试,所以请尝试使用您的数据,看看性能是否有问题
您可以自己选择如何处理孤立记录(这些记录引用了不再存在的ParentID)
像这样在PHP中排序需要事先准备好所有数据,因此请使用类似PDO的fetchAll(PDO::FETCH_ASSOC)
方法,其结果如下:
$data_from_database = array(
array("id" => 1, "parentId" => 0, "description" => "Level 1"),
array("id" => 2, "parentId" => 1, "description" => "Level 1a"),
array("id" => 3, "parentId" => 1, "description" => "Level 1b"),
array("id" => 4, "parentId" => 0, "description" => "Level 2"),
array("id" => 5, "parentId" => 2, "description" => "Level 1a1"),
array("id" => 6, "parentId" => 5, "description" => "Level 1a11a"),
array("id" => 7, "parentId" => 5, "description" => "Level 1a11b"),
array("id" => 8, "parentId" => 9, "description" => "Level 3"),
);
$data_from_database = array(
1 => array("id" => 1, "parentId" => 0, "description" => "Level 1",
"children" => array(), "is_orphan" => false),
...
);
首先,您需要将主键(ID)作为数组的键。下面还将键“children”和“is_orphan”添加到每个记录中
$data_by_id = array();
foreach($data_from_database as $row)
$data_by_id[$row["id"]] = $row + array(
"children" => array(),
"is_orphan" => false
);
这将看起来像这样:
$data_from_database = array(
array("id" => 1, "parentId" => 0, "description" => "Level 1"),
array("id" => 2, "parentId" => 1, "description" => "Level 1a"),
array("id" => 3, "parentId" => 1, "description" => "Level 1b"),
array("id" => 4, "parentId" => 0, "description" => "Level 2"),
array("id" => 5, "parentId" => 2, "description" => "Level 1a1"),
array("id" => 6, "parentId" => 5, "description" => "Level 1a11a"),
array("id" => 7, "parentId" => 5, "description" => "Level 1a11b"),
array("id" => 8, "parentId" => 9, "description" => "Level 3"),
);
$data_from_database = array(
1 => array("id" => 1, "parentId" => 0, "description" => "Level 1",
"children" => array(), "is_orphan" => false),
...
);
现在,它变得很棘手:我们将在数组中循环并添加引用
foreach($data_by_id as &$row)
{
if($row["parentId"] > 0)
{
if(isset($data_by_id[$row["parentId"]]))
$data_by_id[$row["parentId"]]["children"][] = &$row;
else
$row["is_orphan"] = true;
}
}
unset($row); // Clear reference (important).
最后一步是清理数组的“根”。它将包含对重复行的引用
foreach($data_by_id as $id => $row)
{
// If you use this option, you'll remove
// orphaned records.
#if($row["parentId"] > 0)
# unset($data_by_id[$id]);
// Use this to keep orphans:
if($row["parentId"] > 0 AND !$row["is_orphan"])
unset($data_by_id[$id]);
}
在每个步骤后使用print\r($data\u by\u id)
查看发生了什么
如果这证明是一个耗时的操作,请尝试仅通过执行
选择id,parentId FROM…
然后稍后获取元数据(如说明
)来构建树。您还可以将结果存储在Memcache中或序列化到数据库中 对不起,如果这是一个无知的问题。但是我该如何用php组织它呢?biziclop的想法很好。你有三个层次。使用查询获取所有记录,然后对它们运行循环,检查parentId
并分配给数组。我想没有别的办法了。好的,有-使用一个查询来获取顶级记录,然后循环并为每个顶级记录找到它的子记录,然后为每个子记录您将需要一个查询来找到它的子记录,等等。问题是我无法控制数据库。所以一切都必须通过php来完成。我做了一些查找,递归php树遍历似乎是实现这一点的方法。尽管o.o什么都不起作用。除了我的答案中的查询返回的字段之外,您还需要处理哪些数据?更新了我的问题,以进一步反映我的理解,并使我的观点更加清晰(如果这是一个无知的问题)。但是我该如何用php组织它呢?biziclop的想法很好。你有三个层次。使用查询获取所有记录,然后对它们运行循环,检查parentId
并分配给数组。我想没有别的办法了。好的,有-使用一个查询来获取顶级记录,然后循环并为每个顶级记录找到它的子记录,然后为每个子记录您将需要一个查询来找到它的子记录,等等。问题是我无法控制数据库。所以一切都必须通过php来完成。我做了一些查找,递归php树遍历似乎是我要做的事情