sql 知道父节点,查询所有的子节点,运用游标,递归,存储过程
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了sql 知道父节点,查询所有的子节点,运用游标,递归,存储过程相关的知识,希望对你有一定的参考价值。
表tmbm
BPROD char(15) 老爸
BMWHS char(2) 厂号
BMBOMM char(2) method
BSEQ decimal(3, 0) 序号
BCHLD char(15) 儿子
BQREQ decimal(15, 6) 用量
BDEFF decimal(8, 0) 开始生效日期
BDDIS decimal(8, 0) 失效日期
BMSCP decimal(5, 4) 报废率
BBUBB decimal(3, 0) bubb
select sys_connect_by_path(username,'>') "Path"
from tmbm
start with id=1
connect by prior id=parentid;
其中,id是你要遍历的起始点,比如你想从 厂号=XX 的这个父节点开始寻找他所有的子节点,这里就换成 start with BMWHS=XX
然后,connect by prior id=parentid,这里id=parentid,简单解释就是寻找其他记录里,parentid和我的id相同的记录,也就是找子节点。
应该是换成你的BMWHS=BPROD(我不知道你的BPROD BCHLD 和哪个属性是对应的,是BMWHS吗?)
如果是的话就是下面这样(username是你要返回的值,假设你还是要返回 BSEQ 序号)
select sys_connect_by_path(BSEQ,'>') "Path"
from tmbm
start with BMWHS=XX
connect by prior BMWHS=BPROD;追问
我想要输入老爸BPROD后,能够返回儿子BCHLD,序号BSEQ代表的是,加入一个老爸由3个儿子组成,那么三个儿子编号为1,2,3,如果儿子有多层,要返回多层数据。其他的都是tmbm表中的,只要在显示结果的时候,把表中的数据一起显示出来就行。
追答呃,我想想怎么说,能看看你数据具体是怎样的么?
比如数据是这样的:
BPROD BSEQ BCHLD
null 1 2,3,4
1 2 5
1 3 6
1 4 null
2 5 null
3 6 null
那你是要输入序号1,然后得到所有1的儿子,2,3,4,5,6 对吗?那是不是这个BPROD 和BSEQ 一样记录的都是序号呢?
假如老爸bprod是A,由儿子R1,R2组成,R2又由W1,W2组成,我希望的到下面的结果,我要如何写这个存储过程,要用到游标
bprod bchld bseq
A R1 1
A R2 2
R2 W1 1
R2 W2 2
能否给出具体代码,可以追加分数
怎么说呢,你如果是只想得到你说的输出结果的话,我感觉用游标和存储过程没有意义啊,就用我说的select语句就可以得到了,用游标的话我还真不太会,我只能尽我所能写一个游标,存储过程和递归的样板给你,你看看能用到不?
create procedure find_bprod @bprod varchar(15)
as
declare @bchld varchar(15);
declare cursorrr cursor for
select * from tmbm where bprod=@bprod ;
open cursorrr;
fetch next from cursorrr into @bchld;
while(@@fetch_status = 0)
begin
exec find_bprod @bchld ——按你的要求,用递归的方法,寻找子节点是否还有子节点
fetch next from cursorrr into @bchld;
在这里写入代码就可以实现递归,比如对所有子节点的数据进行更新之类的,比如写个update在这里,但是你要查找并返回结果集,这个我觉得好像实现不了啊,游标可以让我们遍历每一个我们查找出来的结果集里的记录,难道要每个递归都生成一个结果子集,然后最后将结果子集合并吗?这就好比你通过搜索得到一个集合,现在你把集合拆散了,一个个去遍历集合的零件,然后再把这些零件凑起来重新组装成一个原集合一半内容的新集合,那还不如一开始就直接从原集合的基础上拆掉不要的,你明白我的意思么。。那还不如就用专门的select语句来剔除不需要的零件更简单啊。
end;
close cursorrr;
deallocate cursorrr;
按你的要求,改了下select,试试这个,他能找到已知老爸为A的所有子节点:
select bprod,bchld,bseq
from tmbm
start with bprod=A
connect by prior bchld=bprod;
有没有一种简单的方法来查询节点的子节点?
【中文标题】有没有一种简单的方法来查询节点的子节点?【英文标题】:Is there a simple way to query the children of a node? 【发布时间】:2010-10-14 03:44:38 【问题描述】:我最近一直在使用Nested Set Model 中的废话。我喜欢为几乎所有有用的操作和视图设计查询。我坚持的一件事是如何选择节点的直接子节点(仅子节点,而不是进一步的后代!)。
老实说,我确实知道一种方法 - 但它涉及无法管理的 SQL 数量。我确信有一个更直接的解决方案。
【问题讨论】:
【参考方案1】:您是否阅读了您发布的文章?它在“查找节点的直接下属”标题下
SELECT node.name, (COUNT(parent.name) - (sub_tree.depth + 1)) AS depth
FROM nested_category AS node,
nested_category AS parent,
nested_category AS sub_parent,
(
SELECT node.name, (COUNT(parent.name) - 1) AS depth
FROM nested_category AS node,
nested_category AS parent
WHERE node.lft BETWEEN parent.lft AND parent.rgt
AND node.name = 'PORTABLE ELECTRONICS'
GROUP BY node.name
ORDER BY node.lft
)AS sub_tree
WHERE node.lft BETWEEN parent.lft AND parent.rgt
AND node.lft BETWEEN sub_parent.lft AND sub_parent.rgt
AND sub_parent.name = sub_tree.name
GROUP BY node.name
HAVING depth <= 1
ORDER BY node.lft;
但是,我所做的(这是作弊)是将嵌套集与邻接列表结合在一起——我在表中嵌入了一个“parent_id”,这样我就可以轻松地询问一个节点的子节点。
【讨论】:
"...我将嵌套集与邻接列表组合在一起..."哈!这就是我正在做的事情。我加入了一个 adj。列表视图,基于 Joe Celko 的查询。这似乎是一大堆代码。甚至链接文章的解决方案也是......冗长。 我的意思是,比较选择所有节点的后代:SELECT * FROM nodes WHERE nodes.leftBound BETWEEN parentLeftBound AND parentRightBound; 好吧,“child_view”很简单,SELECT * FROM nodes WHERE parent_id = 123456 :D +1 表示“作弊”。通常,当使用嵌套集模型时,查询时间比建表更受关注。我发现添加一些其他的东西,比如 ParentId,甚至 Depth 在某些情况下都非常有用,并且添加到表构建中的成本并不高。混合嵌套集邻接列表表很棒。【参考方案2】:在我看来,如果没有子查询或父列冗余,这应该很容易实现!例如,给定父母的左右是已知的:
SELECT child.id
FROM nodes AS child
LEFT JOIN nodes AS ancestor ON
ancestor.left BETWEEN @parentleft+1 AND @parentright-1 AND
child.left BETWEEN ancestor.left+1 AND ancestor.right-1
WHERE
child.left BETWEEN @parentleft+1 AND @parentright-1 AND
ancestor.id IS NULL
也就是说,“从所讨论节点的所有后代中,选择它们与节点之间没有祖先的那些”。
【讨论】:
我想知道哪个答案在性能上更好,这个答案还是接受的帖子。但是,这两种解决方案都有效。这个看起来更紧凑一些。 对于非常大的树,我们发现这在 MySQL 中表现不佳,在 SQL Server 中表现更差,因为它需要在数据库上执行嵌套循环。我们将代码更改为只检索所有后代,然后在我们的应用程序代码中只修剪到子代。 @andreas 这与接受的答案非常相似,不同之处在于它不是计算孩子并过滤到有 1 个孩子的孩子,而是通过查看祖先是否为 NULL 来过滤。这意味着它有更少要做的工作(没有排序和计数步骤)。它应该更快,但我没有测试过。 @user393274 您的答案似乎是在回答 andreas(比较方法),但事实并非如此。您正在回答关于一般使用 SQL 来获取孩子的问题。【参考方案3】:这个更好更小
用户“bobince”几乎拥有它。我想通了并让它为我工作,因为我比大多数人有更多的 MySQL 经验。但是,我明白为什么 bobince 的回答可能会吓跑人们。他的询问不完整。您需要先将 parent_left 和 parent_right 选择到 mysql 变量中。
下面的两个查询假设您的表名为tree
,您的左列名为lft
,右列名为rgt
,并且您的主键名为id
。更改这些值以满足您的需要。此外,检查第一个 select 语句。您会看到我正在查找节点 5 的直接后代。更改数字 5 以查找您想要的任何节点的子节点。
我个人认为这是一个比目前提出的其他查询更时尚、更性感、更有效的查询。
SELECT `lft`, `rgt` INTO @parent_left, @parent_right FROM efm_files WHERE `id` = 5;
SELECT `child`.`id`
FROM `tree` AS `child`
LEFT JOIN `tree` AS `ancestor` ON
`ancestor`.`lft` BETWEEN @parent_left+1 AND @parent_right-1 AND
`child`.`lft` BETWEEN `ancestor`.`lft`+1 AND `ancestor`.`rgt`-1
WHERE
`child`.`lft` BETWEEN @parent_left+1 AND @parent_right-1 AND
`ancestor`.`id` IS NULL
【讨论】:
efm_files 是我的 mysql 数据库中表的名称。将其替换为您自己的数据库表名。 这太棒了 - 我在 SQL 数据库中使用,你的方法就像一个冠军!【参考方案4】:我知道我在做一个死灵帖子, 但这是我的看法。
为什么不在嵌套集中包含“深度”列? 深度列将指示项目的“级别”。
所以,要选择项目的直接子项,只需这样做
select c.*
from tree as p
join tree as c on (c.left > p.left and c.right < p.right and c.depth = p.dept + 1)
where p.id = @parentID
【讨论】:
因为严格来说这不再是嵌套集合,而是层次模型的组合。而且通常情况下,改变模型来解决问题并不是一种选择。【参考方案5】:我也会选择深度列。但是使用
SELECT Child.Node, Child.LEFT, Child.RIGHT
FROM Tree AS Child, Tree AS Parent
WHERE
Child.Depth = Parent.Depth + 1
AND Child.LEFT > Parent.LEFT
AND Child.RIGHT < Parent.RIGHT
AND Parent.LEFT = 1 -- Given Parent Node Left Index
Wikipedia
【讨论】:
请注意,它需要additional深度列以及左右Id。【参考方案6】:我发现Wikipedia link 有很好的最小化答案版本以及选定的答案。
SELECT DISTINCT Child.Name
FROM ModelTable AS Child, ModelTable AS Parent
WHERE Parent.Lft < Child.Lft AND Parent.Rgt > Child.Rgt -- associate Child Nodes with ancestors
GROUP BY Child.Name
HAVING MAX(Parent.Lft) = @parentId -- Subset for those with the given Parent Node as the nearest ancestor
还有,大家尝试用Linq表达,请点击链接:https://***.com/a/25594386/361100
【讨论】:
以上是关于sql 知道父节点,查询所有的子节点,运用游标,递归,存储过程的主要内容,如果未能解决你的问题,请参考以下文章
SQL查询父节点下的所有子节点(包括子节点下的子节点,无限子节点)