Sql 如何从同一表中的父行获取所有子行?
假设我有一个名为my_table的表,看起来像这样:Sql 如何从同一表中的父行获取所有子行?,sql,mysql,Sql,Mysql,假设我有一个名为my_table的表,看起来像这样: id | name | parent_id 1 | Row 1 | NULL 2 | Row 2 | NULL 3 | Row 3 | 1 4 | Row 4 | 1 5 | Row
id | name | parent_id
1 | Row 1 | NULL
2 | Row 2 | NULL
3 | Row 3 | 1
4 | Row 4 | 1
5 | Row 5 | NULL
6 | Row 6 | NULL
7 | Row 7 | 8
8 | Row 8 | NULL
9 | Row 9 | 4
10 | Row 10 | 4
Array
(
[0] => Array
(
[name] => Row 1
[children] => Array
(
[0] => Array
(
[name] => Row 3
[children] =>
)
[1] => Array
(
[name] => Row 4
[children] => Array
(
[0] => Array
(
[name] => Row 9
[children] =>
)
[1] => Array
(
[name] => Row 10
[children] =>
)
)
)
)
)
[1] => Array
(
[name] => Row 2
[children] =>
)
[2] => Array
(
[name] => Row 5
[children] =>
)
[3] => Array
(
[name] => Row 6
[children] =>
)
[4] => Array
(
[name] => Row 8
[children] => Array
(
[0] => Array
(
[name] => Row 7
[children] =>
)
)
)
)
基本上,我希望PHP中的最终数组如下所示:
id | name | parent_id
1 | Row 1 | NULL
2 | Row 2 | NULL
3 | Row 3 | 1
4 | Row 4 | 1
5 | Row 5 | NULL
6 | Row 6 | NULL
7 | Row 7 | 8
8 | Row 8 | NULL
9 | Row 9 | 4
10 | Row 10 | 4
Array
(
[0] => Array
(
[name] => Row 1
[children] => Array
(
[0] => Array
(
[name] => Row 3
[children] =>
)
[1] => Array
(
[name] => Row 4
[children] => Array
(
[0] => Array
(
[name] => Row 9
[children] =>
)
[1] => Array
(
[name] => Row 10
[children] =>
)
)
)
)
)
[1] => Array
(
[name] => Row 2
[children] =>
)
[2] => Array
(
[name] => Row 5
[children] =>
)
[3] => Array
(
[name] => Row 6
[children] =>
)
[4] => Array
(
[name] => Row 8
[children] => Array
(
[0] => Array
(
[name] => Row 7
[children] =>
)
)
)
)
因此,我希望它获取parent_id为null的所有行,然后递归地查找所有嵌套的子行
下面是我遇到麻烦的部分:
如何通过对数据库的一次调用来实现这一点
我相信我可以用一个简单的select语句来实现,然后让PHP使数组看起来像这样,但我希望这可以通过某种奇特的db连接或类似的方式来实现。AFAIK这是不可能的。除非您编写一些存储过程来完成这项工作。我不知道如何从单个数据库调用中获取这样的数组。mysql查询返回一个类似于表的数据集,它总是基于列的。因此,答案是你不能 但是,可以进行非常智能的基于树的查询。关于这一点,可以找到一本非常有趣的书 在mysql以外的其他系统上,可以实现您想要的
但仍然没有现成的数组。我不知道MySQL,但在SQL Server(我相信这是ANSI-SQL)中,这是通过CTE(公共表表达式)完成的,它采用以下形式:
WITH MyCTE
(
-- Non-recursive anchor query
UNION ALL
-- Recursive portion that typically JOINs MyCTE to some other table
)
SELECT * FROM MyCTE;
MySQL中没有递归查询,但有嵌套集的思维方式。完整的参考资料就在这里:在MySQL中,您可以创建存储过程,它将返回您需要的内容。您可以查看MSSQL的简单示例。但MySQL也很容易实现这里的问题是,Id并不是按照遍历树的顺序存储的。如果您通过构建树一次来解决此问题,然后按照遍历节点的顺序将所有节点复制回另一个分配Id的表中,下次您将能够通过简单扫描select语句的前向结果来填充树,如 从my_表中选择*按Id排序
若树经常更改,此解决方案将不起作用,因为必须重新生成表。这可以通过将Id最初增加一个大的数字(比如1000)来解决,这样就不必每次都重新编号,因为您可以从间隙中分配新的节点Id。如果树的高度很小,使用分数作为键也可以很好地工作。最简单的方法就是用PHP来实现。我必须在Symfony中做一些类似的事情,但是它应该很容易阅读和适应。从表行中的数组开始
public function executeGetTree(sfWebRequest $request)
{
$rows = Doctrine_Core::getTable('TreeNode')->findAll();
$treeNodes = $rows->toArray();
//set up new array to store children for each parent node
$nodesContainer = array();
foreach ($treeNodes as $node){
$parentId = $node['parent_id'];
//if node has no parent, it is a root node
$nodesContainer[isset($parentId)? $parentId : 'root'][] = $node;
}
$tree = array();
//recursively get descendents for each root node
foreach($nodesContainer['root'] as $rootNode)
{
$tree[] = $this->getChildren($nodesContainer, array($rootNode));
}
print_r($tree);
return sfView::NONE;
}
private function getChildren(&$container, $parentNode){
$children = array();
foreach ($parentNode as $node){
if(isset($container[$node['id']])){
$node['children'] = $this->getChildren($container, $container[$node['id']]);
}
$children[] = $node;
}
return $children;
}
我希望这可以通过加入某种奇特的db或类似的方式来实现
你应该考虑听起来是多么的不可能。
只考虑树中的一个分支,从1到4–9和10
您将如何在MySql结果或任何DBMS中的一行中可视化关系
对于分层结果,我能想到的唯一明智的选择是XML,但您不想去那里,因为它可以在PHP中的base record.parent结构上做得更好,而不是解析XML。可能类似于此,根据需要添加级别:
SELECT
d1.*,
d2.`name` AS '2nd Level',
d3.`name` AS 'Top Level'
FROM `my_table` AS d1
LEFT JOIN `my_table` AS d2 ON d1.parent_id=d2.id
LEFT JOIN `my_table` AS d3 ON d2.parent_id=d3.id
递归查询在Oracle和最新的PostgreSQl上也可用,但在MySQL上不可用。