我不确定这是否完全符合我的措辞,但我们开始吧:我试图弄清楚如何在 php 中创建一个递归循环,该循环基本上检查子列是否为空 - 如果该子元素列有一个空值,然后它使用父ID递归地遍历其祖先,直到找到具有该列的值的父,然后将该父值放入原始子列中。由于我刚开始使用 php,但我对数据库和 mysql 有深入的了解,因此我对此感到非常困惑。任何帮助和代码示例都会很棒。
2 回答
关于使用邻接列表模型存储分层数据的警告:它以易于创建和更新表为代价换取了重新获取数据的效率低下。我个人在我的项目中使用了Closure Tables,因为即使弄清楚如何在其中获取数据以及如何更新它们是很疯狂的,但在重新获取数据方面效率要高得多。如果您有 Closure Tables,您可以使用一个查询来获取节点的所有具有信息的父节点的列表,并使用 ORDER BY Distance LIMIT 1 来获取您想要的父节点作为您的答案。使用嵌套集也可以是一种选择,尽管我对它们知之甚少。在继续之前,您应该研究这些并考虑您的选择。
这是您现在拥有的邻接列表:
$target = 4; //whatever ID
$db = new mysqli(HOST, USERNAME, PASSWORD, DATABASE);
if($db->connect_errno > 0){
die('Unable to connect to database [' . $db->connect_error . ']');
}
$statement = $db->prepare("SELECT ParentID, Audience FROM things WHERE ChildID = ?");
$audience = NULL;
$ChildID = $target; // starts as same value
while(!isset($audience) || !isset($ChildID)) { //This assumes that the top ParentID is null; you might have to adjust it
$statement->bind_param('i', $ChildID);
$statement->execute();
$result = $statement->get_result();
while($row = $result->fetch_assoc()){
if(!isset($row['Audience']) && !isset($audience)) {
$ChildID = isset($row['ParentID'])?$row['ParentID']:NULL;
} else {
$audience = $row['Audience'];
}
}
$result->free();
}
if(isset($audience)) {
if($target == $ChildID) { //it was found on that first try
echo $audience.' was found for '.$target;
} else {
$statement = $db->prepare("UPDATE things SET Audience = ? WHERE ChildID = ?");
$statement->bind_param('si', $audience, $target);
$statement->execute();
echo $audience.' was set for '.$target;
}
} else {
echo 'No audience was found or set for '.$target;
}
$db->close();
请注意,bind_param 的第一个参数关心您的绑定对象是什么类型(字符串、整数、小数、blob)。你可能需要查一下。
请提供示例表/字段。我们不知道您是指一张桌子还是几张桌子。
您的 php 代码可能看起来像这样(查询内容是伪代码)
function updateChild($ChildID,$ParentID=-1)
{
//use mysqlquery or whatever
if($ParentID==-1)
select field_value,parent_id from mytable where rowid=$ChildID;
else
select field_value,parent_id from mytable where parentid=$ParentID;
$candidate_value=$row['field_value'];
$fallback_parent=$row['parent_id']
if ( is_null($candidate_value))
updateChild($ChildID, $fallback_parent)
else
update mytable set field_value=$candidate_value where $ChildID=$ChildID
}
想法是您首先获取当前字段值和 parentID 以防万一。如果结果为空,则再次调用相同的函数,传入子项或 rowid 以及下一个要检查的父项。如果父母证明是好的,它会使用一直传递的子值进行更新。请注意,如果在第一次尝试时确实有值,上面的代码将使用“自身”更新子值,因此应该通过检查 parentid 是否为 -1 来解决这个问题。