SQL中树节点的查找,请各位帮忙 ( 积分: 200 )

  • 主题发起人 主题发起人 freeskyzu
  • 开始时间 开始时间
F

freeskyzu

Unregistered / Unconfirmed
GUEST, unregistred user!
现在有一个表,结构如下(我给出SQL语句,请各位复制就可以了)
Create table tree
(parent int,
child int,
names varchar(12),
constraint tree_uk unique(parent,child)
)
insert into tree (parent,child) values(0,0,'总公司')
insert into tree (parent,child) values(0,1,'北京公司')
insert into tree (parent,child) values(0,2,'上海公司')
insert into tree (parent,child) values(0,3,'广州公司')
insert into tree (parent,child) values(0,4,'长沙公司')
insert into tree (parent,child) values(0,5,'太原公司')
insert into tree (parent,child) values(1,10,'总公司')
insert into tree (parent,child) values(1,11,'北京1公司')
insert into tree (parent,child) values(1,12,'北京2公司')
insert into tree (parent,child) values(1,13,'北京3公司')
insert into tree (parent,child) values(1,14,'北京4公司')
insert into tree (parent,child) values(1,15,'北京5公司')
insert into tree (parent,child) values(11,111,'北京11公司')
insert into tree (parent,child) values(11,112,'北京12公司')
insert into tree (parent,child) values(11,113,'北京13公司')
insert into tree (parent,child) values(11,114,'北京14公司')
insert into tree (parent,child) values(11,115,'北京15公司')
。。。。。。
有以下几个问题:
一、 给出一个节点,找出所有的它的子节点
二、 给出一个节点,找出所有的它的父节点
三、 给出一个节点,找出所有的它的同级节点
四、 给出一个节点,找出它的最顶一个节点(祖宗)(没有上级节点了)
五、 给出一个节点,找出它的最底一个节点(最小的子孙)(没有下级节点了)
 
树的问题是常见的问题,很简单的,但也很重要。一般情况下建立一个code(varchar)辅助字段就行了(比如001,002,001001,001002等等等),没必要建立parent 和child字段。其实你见的表已经回答了你的问题,呵呵
 
像树的问题一般牵涉到递归思想,用sql语句写可能比较麻烦,如用delphi等语句写就很简单了,树的操作我写过n遍了,把我以前写的一个小例子贴给你:
id(varchar) ,code(varchar) ,name(varchar)
1 001 ls
2 001001 lu
3 002 xx
4 002001 gg

procedure TForm1.Button1Click(Sender: TObject);
var
i: integer;
tempNode: TcxTreeListNode;
begin
i:= 0;
cxTreeList1.BeginUpdate;
cxTreeList1.Clear;
ADOQuery1.First;
with ADOQuery1 do
while not eof do
begin
tempNode:= GetParent(Fields[1].AsString);
if tempNode = nil then
begin
cxTreeList1.Nodes.Root.AddChild;
cxTreeList1.Nodes.AbsoluteItems.Values[0]:= Fields[1].AsString;
cxTreeList1.Nodes.AbsoluteItems.Values[1]:= Fields[2].AsString;
inc(i);
Next;
end
else
begin
tempNode.AddChild;
cxTreeList1.Nodes.AbsoluteItems.Values[0]:= Fields[1].AsString;
cxTreeList1.Nodes.AbsoluteItems.Values[1]:= Fields[2].AsString;
inc(i);
Next;
end;
end;
cxTreeList1.EndUpdate;

cxTreeList1.FullExpand;
end;

function TForm1.GetParent(code: string): TcxTreeListNode;
var
i: integer;
strLen: integer;
tempStr: string;
begin
Result:= nil;
strLen:= length(code)-3;
tempStr:= copy(code,0,strLen);
for i:= 0 to cxTreeList1.nodes.Count-1 do
begin
if cxTreeList1.Nodes.AbsoluteItems.Values[0] = tempStr then
begin
Result:= cxTreeList1.Nodes.AbsoluteItems;
Break;
end;
end;
end;
(注: adoquery.sql = select * from a order by code asc)
 
首先谢谢lisongmagic 的DELPHI解法,但我需要在数据库中用SQL处理这个问题,另外就是还有以下需求:
最重要的一点就是从一个子节点到另一个子节点经过的所有节点

分不够的话可以另外开贴给分.QQ70636604
 
用三个字段是绝佳的结构,非常好用。

ID,ParentID,IDPath,
1,0,1/
2,1,1/2
3,2,1/2/3
4.2.1/2/4
 
是否可以详细些呢
 
不是要将所有的节点都存在一个字段里面吧?以前想过这样,但是考虑到空间就放弃了。以前都是在DELPHI中处理,现在因为需要在SQL中用,所以没办法请各位帮手了。
 
这是我程序中的部分代码,送给你了!将相应的表名、字段替换成你的就行了。直接调用这个函数返回的就是你需要的在该节点下的公司。如:select * from dbo.getsubtreeinfo(0)
CREATE FUNCTION dbo.GetSubtreeInfo ( @manager_id AS char(6))
RETURNS @treeinfo table ( [单位编码] [char] (6) NOT NULL, [单位名称] [char] (30) NOT NULL, [上级编码] [char] (6) NULL, [级别] [int] NOT NULL
) with encryption
AS
BEGIN
DECLARE @level AS int
SELECT @level = 0
INSERT INTO @treeinfo
SELECT [单位编码], [单位名称], [上级编码], @level
FROM [单位基本信息]
WHERE [单位编码] = @manager_id
WHILE @@ROWCOUNT > 0
BEGIN
SET @level = @level + 1
INSERT INTO @treeinfo
SELECT E.[单位编码], E.[单位名称], E.[上级编码], @level
FROM [单位基本信息] AS E JOIN @treeinfo AS T
ON E.[上级编码] = T.[单位编码] AND T.[级别] = @level - 1
END
RETURN
END
 
这种表结构处理起来挺麻烦的,我给你一个选择所有子节点的存储过程吧:

create procedure SelTest
@pid int,
@name varchar(32)
as
begin
select * into #Aa from tree where parent=@pid
select * into #Ab from tree where 1<>1
select * into #Ac from tree where 1<>1
while Exists(select 1 from #Aa)
begin
delete from #Ac
insert into #Ac select * from #Aa
insert into #Ab select * from #Aa
delete from #Aa
insert into #Aa select * from tree
where parent in (select child from #Ac)
end
select * from #Ab
end

调用: exec seltest 1, '总公司'
 
感谢wqch88,dreamisx两位提供的方法。以此方法可推出返回父节点的方法。但是如何返回从一个子节点到另一个子节点的全部路经呢?
 
给你个思路吧,时间比较紧,代码就不写了。
查找这两个节点的父节点,看是否相同,如果不同继续查找,直到相同为止。
 
参考我以前回答的贴子:
http://www.delphibbs.com/delphibbs/dispq.asp?lid=3643661
 
问题解决了没?别忘结帐啊?:)
 
还没有呢,请各位给于支持。主要是路径部分
 
select a.nID,a.sName,b.nID,b.sName,c.nID,c.sName,d.nID,a.sName from t_table a
left join t_table b on b.nID=a.nPartentID
left join t_table c on c.nID=b.nPartentID
left join t_table d on d.nID=c.nPartentID
....
 
感谢各位。希望有时间多交流。请各位留下QQ号
 
后退
顶部