如何使用 PHP 和 MySQL 将父子(邻接)表转换为嵌套集?
我花了几个小时试图在网上找到这个问题的解决方案。我发现了很多关于如何从嵌套集转换为邻接集的示例......但很少有相反的情况。我发现的示例要么不起作用,要么使用 MySQL 过程。不幸的是,我无法使用该项目的过程。我需要一个纯 PHP 解决方案。
我有一个使用下面的邻接模型的表:
id parent_id category
1 0 Books
2 0 CD's
3 0 Magazines
4 1 Books/Hardcover
5 1 Books/Large Format
6 3 Magazines/Vintage
我想将其转换为下面的嵌套集表:
id left right category
0 1 14 Root Node
1 2 7 Books
4 3 4 Books/Hardcover
5 5 6 Books/Large Format
2 8 9 CD's
3 10 13 Magazines
6 11 12 Magazines/Vintage
这是我需要的图像:
我有一个函数,基于此论坛帖子中的伪代码 (http://www.sitepoint.com/forums/showthread.php?t=320444),但它不起作用。我得到的多行的左侧值相同。这不应该发生。
<?php
/**
--
-- Table structure for table `adjacent_table`
--
CREATE TABLE IF NOT EXISTS `adjacent_table` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`father_id` int(11) DEFAULT NULL,
`category` varchar(128) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=8 ;
--
-- Dumping data for table `adjacent_table`
--
INSERT INTO `adjacent_table` (`id`, `father_id`, `category`) VALUES
(1, 0, 'ROOT'),
(2, 1, 'Books'),
(3, 1, 'CD''s'),
(4, 1, 'Magazines'),
(5, 2, 'Hard Cover'),
(6, 2, 'Large Format'),
(7, 4, 'Vintage');
--
-- Table structure for table `nested_table`
--
CREATE TABLE IF NOT EXISTS `nested_table` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`lft` int(11) DEFAULT NULL,
`rgt` int(11) DEFAULT NULL,
`category` varchar(128) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;
*/
mysql_connect('localhost','USER','PASSWORD') or die(mysql_error());
mysql_select_db('DATABASE') or die(mysql_error());
adjacent_to_nested(0);
/**
* adjacent_to_nested
*
* Reads a "adjacent model" table and converts it to a "Nested Set" table.
* @param integer $i_id Should be the id of the "root node" in the adjacent table;
* @param integer $i_left Should only be used on recursive calls. Holds the current value for lft
*/
function adjacent_to_nested($i_id, $i_left = 0)
{
// the right value of this node is the left value + 1
$i_right = $i_left + 1;
// get all children of this node
$a_children = get_source_children($i_id);
foreach ($a_children as $a)
{
// recursive execution of this function for each child of this node
// $i_right is the current right value, which is incremented by the
// import_from_dc_link_category method
$i_right = adjacent_to_nested($a['id'], $i_right);
// insert stuff into the our new "Nested Sets" table
$s_query = "
INSERT INTO `nested_table` (`id`, `lft`, `rgt`, `category`)
VALUES(
NULL,
'".$i_left."',
'".$i_right."',
'".mysql_real_escape_string($a['category'])."'
)
";
if (!mysql_query($s_query))
{
echo "<pre>$s_query</pre>\n";
throw new Exception(mysql_error());
}
echo "<p>$s_query</p>\n";
// get the newly created row id
$i_new_nested_id = mysql_insert_id();
}
return $i_right + 1;
}
/**
* get_source_children
*
* Examines the "adjacent" table and finds all the immediate children of a node
* @param integer $i_id The unique id for a node in the adjacent_table table
* @return array Returns an array of results or an empty array if no results.
*/
function get_source_children($i_id)
{
$a_return = array();
$s_query = "SELECT * FROM `adjacent_table` WHERE `father_id` = '".$i_id."'";
if (!$i_result = mysql_query($s_query))
{
echo "<pre>$s_query</pre>\n";
throw new Exception(mysql_error());
}
if (mysql_num_rows($i_result) > 0)
{
while($a = mysql_fetch_assoc($i_result))
{
$a_return[] = $a;
}
}
return $a_return;
}
?>
这是上述脚本的输出。
插入
nested_table
(id
,lft
、rgt
、类别
) VALUES( NULL、“2”、“5”、“精装”)插入
nested_table
(id
,lft
、rgt
、类别
) VALUES( NULL、“2”、“7”、“大格式”)插入
nested_table
(id
,lft
、rgt
、类别
) VALUES( NULL、“1”、“8”、“书籍”)插入
nested_table
(id
,lft
、rgt
、类别
) VALUES( NULL、“1”、“10”、“CD”)插入
nested_table
(id
,lft
、rgt
、类别
) VALUES( NULL、“10”、“13”、“复古”)插入
nested_table
(id
,lft
、rgt
、类别
) VALUES( NULL、“1”、“14”、“杂志”)插入
nested_table
(id
,lft
、rgt
、类别
) VALUES( NULL、“0”、“15”、“根”)
如您所见,有多个行共享“1”的 lft 值,同样适用于“2” 在嵌套集中,左和右的值必须是独一无二的。以下是如何手动对嵌套集中的左侧和右侧 ID 进行编号的示例:
图片来源:Gijs Van Tulder,参考文章
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
我在网上找到了答案,并更新了此页面上的问题,以向其他人展示它是如何完成的。
更新 - 问题已解决
首先,我错误地认为需要更改源表(相邻列表格式的表)以包含源节点。事实并非如此。其次,我 找到了一个类 通过 BING 就可以了。我已经针对 PHP5 对其进行了更改,并将原作者的 mysql 相关位转换为基本 PHP。他正在使用一些 DB 类。如果需要,您可以稍后将它们转换为您自己的数据库抽象类。
显然,如果您的“源表”有其他列想要移动到嵌套集表,则必须调整下面类中的 write 方法。
希望这能帮助其他人在未来避免同样的问题。
这是输出:
I found an answer online and updated the question on this page to show others how it is done.
UPDATE - PROBLEM SOLVED
First off, I had mistakenly believed that the source table (the one in adjacent-lists format) needed to be altered to include a source node. This is not the case. Secondly, I found a class via BING that does the trick. I've altered it for PHP5 and converted the original author's mysql related bits to basic PHP. He was using some DB class. You can convert them to your own database abstraction class later if you want.
Obviously, if your "source table" has other columns that you want to move to the nested set table, you will have to adjust the write method in the class below.
Hopefully this will save someone else from the same problems in the future.
Here is the output:
bash 转换:
Bash converting: