CSDN-CSDN社区-MS-SQL Server-疑难问题

收藏 一条超难的树形结构表的sql,请大家帮忙[问题点数:100,结帖人:BlackCodeBoy]

  • BlackCodeBoy
  • (把握今天,感谢上天)
  • 等 级:
  • 结帖率:
楼主发表于:2008-05-06 10:19:43
有一个表名为:T
结构如下:
id ---int
parentid---int 上层的父节点
sname--varchar(50)

如有以下数据:
id  parentid  sname
1  -1        根节点
2  1        节点1
3  1        节点2
4  2        节点3
5  2        节点4
6  3        节点5
7  3        节点6
7  6        节点7

假如:我要得到某个节点下所有的最底层的节点数据怎么实现:
如:我要得到id=3 的所有最底层的数据是:
id  parentid  sname
7  3          节点6
7  6          节点7
请大家多多帮忙,谢谢!


回复次数:60
#1楼 得分:30回复于:2008-05-06 10:22:16
#2楼 得分:20回复于:2008-05-06 10:24:48
#3楼 得分:0回复于:2008-05-06 10:25:24
第一个是查找子节点的

第二个是查找父节点的
  • liangCK用户头像
  • liangCK
  • (小梁 爱 兰儿 (梁爱兰))
  • 等 级:
  • 2

    2

#4楼 得分:20回复于:2008-05-06 10:27:23
  • playwarcraft用户头像
  • playwarcraft
  • (时间就像乳沟,挤挤还是有的)
  • 等 级:
#5楼 得分:0回复于:2008-05-06 10:28:27
这个貌似深度排序广度排序的展树函数,csdn上很多~~~
#6楼 得分:20回复于:2008-05-06 10:32:38
#7楼 得分:10回复于:2008-05-06 10:33:49
SQL code
create table tb(id int, parentid int, sname varchar(10))
insert into tb values(1 , -1 ,        '根节点') 
insert into tb values(2 ,  1 ,        '节点1') 
insert into tb values(3 ,  1 ,        '节点2') 
insert into tb values(4 ,  2 ,        '节点3') 
insert into tb values(5 ,  2 ,        '节点4') 
insert into tb values(6 ,  3 ,        '节点5') 
insert into tb values(7 ,  3 ,        '节点6') 
insert into tb values(7 ,  6 ,        '节点7') 
go

--查询指定节点及其所有子节点的函数 
CREATE FUNCTION f_Cid(@ID int) RETURNS @t_Level TABLE(ID int,Level int) 
AS 
BEGIN 
  DECLARE @Level int 
  SET @Level=1 
  INSERT @t_Level SELECT @ID,@Level 
  WHILE @@ROWCOUNT>0 
  BEGIN 
    SET @Level=@Level+1 
    INSERT @t_Level SELECT a.ID,@Level 
    FROM tb a,@t_Level b 
    WHERE a.parentid=b.ID 
    AND b.Level=@Level-1 
  END 
  RETURN 
END 
GO 

SELECT distinct a.* FROM tb a,f_Cid(3) b WHERE a.ID=b.ID and a.id not in(select parentid from tb)

drop table tb
drop function dbo.f_cid

/*
id          parentid    sname      
----------- ----------- ---------- 
7           3           节点6
7           6           节点7

(所影响的行数为 2 行)
*/

  • utpcb用户头像
  • utpcb
  • (无欲则刚)
  • 等 级:
#8楼 得分:0回复于:2008-05-06 10:43:21
WITH
TREE AS(
    SELECT * FROM T
    WHERE parentid = 3  -- 要查询的父 id
    UNION ALL
    SELECT T * FROM T, TREE
    WHERE T.parentid = TREE.id
)
SELECT * FROM TREE


2005的这个方法最好
  • hery2002用户头像
  • hery2002
  • (苦*行*僧)
  • 等 级:
  • 2

    2

#9楼 得分:0回复于:2008-05-06 10:49:38
Mark.
  • ojuju10用户头像
  • ojuju10
  • (永州之野产异蛇—永州异蛇!)
  • 等 级:
#10楼 得分:0回复于:2008-05-06 11:00:45
SQL code

create table tb(id int,parentid int,sname varchar(10))
insert into tb select 1 , -1     ,    '根节点' 
insert into tb select 2 ,  1     ,    '节点1' 
insert into tb select 3 ,  1     ,    '节点2' 
insert into tb select 4 ,  2     ,    '节点3' 
insert into tb select 5 ,  2     ,    '节点4' 
insert into tb select 6 ,  3     ,    '节点5' 
insert into tb select 7 ,  3     ,    '节点6' 
insert into tb select 7 ,  6     ,    '节点7' 
go

alter FUNCTION f_Cid(@ID int)
RETURNS @t_Level TABLE(ID int,Level int)
AS
BEGIN
    DECLARE @Level int
    SET @Level=1
    INSERT @t_Level SELECT @ID,@Level
    WHILE @@ROWCOUNT>0
    BEGIN
        SET @Level=@Level+1
        INSERT @t_Level SELECT a.ID,@Level
        FROM tb a,@t_Level b
        WHERE a.parentID=b.ID
            AND b.Level=@Level-1
    END
    delete a from  @t_level a
    where exists(select 1 from @t_level where a.level
  • ojuju10用户头像
  • ojuju10
  • (永州之野产异蛇—永州异蛇!)
  • 等 级:
#11楼 得分:0回复于:2008-05-06 11:04:32

with cet
as
(
select * from tb
where id=3
union all
select a.* from tb a,cet b
where b.id=a.parentid
)
select * from cet
where id <>3
  • Amy08用户头像
  • Amy08
  • (Amy)
  • 等 级:
#12楼 得分:0回复于:2008-05-06 11:56:12
create table #c(id int,parentid int,sname varchar(10))
insert into #c select 1 , -1    ,    '根节点'
insert into #c select 2 ,  1    ,    '节点1'
insert into #c select 3 ,  1    ,    '节点2'
insert into #c select 4 ,  2    ,    '节点3'
insert into #c select 5 ,  2    ,    '节点4'
insert into #c select 6 ,  3    ,    '节点5'
insert into #c select 7 ,  3    ,    '节点6'
insert into #c select 7 ,  6    ,    '节点7'
go

WITH cet AS(
    SELECT * FROM #c
    WHERE parentid = 3  -- 要查询的父 id
    UNION ALL
    SELECT a.* FROM #c a inner join cet b
    on a.parentid = b.id
)
SELECT * FROM cet where id not in (select parentid from cet)
#13楼 得分:0回复于:2008-05-06 15:23:52
sql吗?看不懂耶~~还要多多努力!!
  • fuanwei用户头像
  • fuanwei
  • (草原上狂奔的蜗牛)
  • 等 级:
#14楼 得分:0回复于:2008-05-06 16:40:43
SQL code
drop table tb
create table tb(id int,parentid int,sname varchar(10))
insert into tb select 1 , -1     ,    '根节点' 
insert into tb select 2 ,  1     ,    '节点1' 
insert into tb select 3 ,  1     ,    '节点2' 
insert into tb select 4 ,  2     ,    '节点3' 
insert into tb select 5 ,  2     ,    '节点4' 
insert into tb select 6 ,  3     ,    '节点5' 
insert into tb select 7 ,  3     ,    '节点6' 
insert into tb select 8 ,  6     ,    '节点7' 
go

alter FUNCTION f_Cid(@ID int)
RETURNS @t_Level TABLE(Level int)
AS
BEGIN
    DECLARE @Level int
    set @Level=0
    if exists(select * from tb where parentid=@ID)
    begin
    INSERT @t_Level select id from tb where parentid=@ID
    while exists(select * from tb where parentid=@ID and id>@Level)
    begin
    set @Level=(select top 1 id from tb where parentid=@ID and id>@Level)
    --set @ID=@Level
    INSERT @t_Level select Level from dbo.f_Cid(@Level)
    end
    end
    RETURN
END
GO

select * 
from f_cid(3)

变换一下就行了
  • zuo_hy用户头像
  • zuo_hy
  • (从前的秋天)
  • 等 级:
#15楼 得分:0回复于:2008-05-06 20:40:20
没弄懂,根据表结构树如下:
  根
  / \
  1  2
    / \
    3  4
  / \
  5  6
    /
    7.
假如:我要得到某个节点下所有的最底层的节点数据怎么实现:
如:我要得到id=3 的所有最底层的数据是:
id  parentid  sname
7  3          节点6
7  6          节点7

为什么没有结点5?
有哪位帮我解答下,
  • zuo_hy用户头像
  • zuo_hy
  • (从前的秋天)
  • 等 级:
#16楼 得分:0回复于:2008-05-06 20:45:13
我的回复呢?
  • zuo_hy用户头像
  • zuo_hy
  • (从前的秋天)
  • 等 级:
#17楼 得分:0回复于:2008-05-06 20:49:01
又见大大了,老乌龟也5颗星星了,
#18楼 得分:0回复于:2008-05-07 00:10:29
看不懂耶
#19楼 得分:0回复于:2008-05-07 05:17:01
我的回复呢?
  • ciitc2用户头像
  • ciitc2
  • (ciitc2)
  • 等 级:
#20楼 得分:0回复于:2008-05-07 09:41:36
经验之谈啊,不错,多学习……这里宝贵资料挺多
#21楼 得分:0回复于:2008-05-07 09:57:05
引用 15 楼 zuo_hy 的回复:
没弄懂,根据表结构树如下:
  根
  / \
  1  2
    / \
    3  4
  / \
  5  6
    /
    7.
假如:我要得到某个节点下所有的最底层的节点数据怎么实现: 
如:我要得到id=3 的所有最底层的数据是: 
id  parentid  sname 
7  3          节点6 
7  6          节点7 
为什么没有结点5?
有哪位帮我解答下,

支持
  • xhj104用户头像
  • xhj104
  • (海风)
  • 等 级:
#22楼 得分:0回复于:2008-05-07 11:23:13
ORACLE中查询
select t.* from t_pub_menu  t
start  with menuid=20000
connect by parentmenuid = prior menuid
#23楼 得分:0回复于:2008-05-07 11:47:17
如:我要得到id=3 的所有最底层的数据是:
id  parentid  sname
7  3          节点6
7  6          节点7
请大家多多帮忙,谢谢!

最底层是
id  parentid  sname
6  3        节点5
7  6        节点7

#24楼 得分:0回复于:2008-05-07 14:25:13
好象很复杂啊,看来要更加努力学习才是啊!!
  • s32702用户头像
  • s32702
  • (随便吧)
  • 等 级:
#25楼 得分:0回复于:2008-05-07 15:14:37
说实在的,没看明白
#26楼 得分:0回复于:2008-05-07 16:50:45
为什么不考虑一下用递规呢
#27楼 得分:0回复于:2008-05-07 18:05:48
fuck you
http://edmundyau123.free-web-hosting.biz
#28楼 得分:0回复于:2008-05-07 21:49:24
有点意思,研究一下,
#29楼 得分:0回复于:2008-05-07 22:27:33
问题到底解决了没有?
#30楼 得分:0回复于:2008-05-07 23:03:42
引用 1 楼 kk19840210 的回复:
SQL code--测试数据CREATETABLEtb(IDchar(3),PIDchar(3),Namenvarchar(10))INSERTtbSELECT'001',NULL,'山东省'UNIONALLSELECT'002','001','烟台市'UNIONALLSELECT'004','002','招远市'UNIONALLSELECT'003','001','青岛市'UNIONALLSELECT'005',NULL,'四会市'UNIONALLSELECT'006','005','清远市'UNIONALLSELECT'007','006','小分市'GO--查询指定节点及其所有子节点的函数CREATEFUNCTIONf_Cid(@IDchar(3))RETURNS@t_LevelTABLE(IDch…

悄悄的问一句:

在2005中执行此功能函数成功,但是在2000中执行失败,错误提示对
INSERT @t_Level SELECT a.ID,@Level
        FROM tb a,@t_Level b
        WHERE a.PID=b.ID
            AND b.Level=@Level-1
这句,理由是
服务器: 消息 446,级别 16,状态 9,过程 f_Cid,行 11
无法解决 equal to 操作的排序规则冲突。
#31楼 得分:0回复于:2008-05-07 23:17:55
引用 6 楼 zjcxc 的回复:
-- sql 2005 可以直接查询
SQL code;WITHTREEAS(SELECT*FROMTWHEREparentid=3--要查询的父 idUNIONALLSELECTT*FROMT, TREEWHERET.parentid=TREE.id
)SELECT*FROMTREE


问个问题,这个只有2005中才有效吗?
#32楼 得分:0回复于:2008-05-07 23:36:14
引用 4 楼 liangCK 的回复:
SQL codecreatetabletb(idint,parentidint,snamevarchar(10))insertintotbselect1,-1,'根节点'insertintotbselect2,1,'节点1'insertintotbselect3,1,'节点2'insertintotbselect4,2,'节点3'insertintotbselect5,2,'节点4'insertintotbselect6,3,'节点5'insertintotbselect7,3,'节点6'insertintotbselect7,6,'节点7'goCREATEFUNCTIONf_Cid(@IDint)RETURNS@t_LevelTABLE(IDint,Levelint)ASBEGINDECLARE@LevelintSET@Level=1INSERT@t…


在2000中使用这个方法并未出现无法解决 equal to 操作的排序规则冲突。

难道是数值形和字符型的差别
  • xmxoxo用户头像
  • xmxoxo
  • (xmxoxo)
  • 等 级:
#33楼 得分:0回复于:2008-05-08 01:20:17
mark
#34楼 得分:0回复于:2008-05-08 07:46:00
mark
#36楼 得分:0回复于:2008-05-08 09:23:15
一个表名为:T
结构如下:
id ---int
parentid---int 上层的父节点
sname--varchar(50)

如有以下数据:
id  parentid  sname
1  -1        根节点
2  1        节点1
3  1        节点2
4  2        节点3
5  2        节点4
6  3        节点5
7  3        节点6
7  6        节点7


也可以考虑使用如下的表T_C来保存父子关系(加入一个distance字段来保存到父节点的层次):
id  parentid  distance
1  1        0
2  1        1
3  1        1
4  1        2
4  2        1
5  1        2
5  2        1
6  1        2
6  3        1
7  1        1
7  3        2
7  1        3
7  3        2
7  6        1

如果你的父子表数据不是很大的话,可以考虑这种设计,这样虽然插入数据时有些麻烦,但查询起来比较方便
#37楼 得分:0回复于:2008-05-08 12:16:04
引用 36 楼 oldseasoul 的回复:
一个表名为:T
结构如下:
id ---int
parentid---int 上层的父节点
sname--varchar(50)

如有以下数据:
id  parentid  sname
1  -1        根节点
2  1        节点1
3  1        节点2
4  2        节点3
5  2        节点4
6  3        节点5
7  3        节点6
7  6        节点7


也可以考虑使用如下的表T_C来保存父子关系(加入一个distance字段来保存到父节点的层次):
id  parentid  …

你的说法也就相当于上面写的这段实现的功能
  begin
    INSERT @t_Level select id from tb where parentid=@ID
    while exists(select * from tb where parentid=@ID and id>@Level)
    begin
    set @Level=(select top 1 id from tb where parentid=@ID and id>@Level)
    --set @ID=@Level
    INSERT @t_Level select Level from dbo.f_Cid(@Level)
    end
    end
#38楼 得分:0回复于:2008-05-08 14:51:53
已知部门组织结构:
--------------------------------------------------------
[PDeptID]    [DeptID]  [Name]  [Description]
--------------------------------------------------------
NULL          1        A
1              2        B 
1              3        C
1              4        D
3              5        E
3              6        F
...
---------------------------------------------------------
查某部门节点下所有节点函数如下:

CREATE  FUNCTION [dbo].[F_UM_DPTS]
(@DeptID INT) 
RETURNS @RET_UM_DPTS TABLE
(
[PDeptID] [int] NULL ,
[DeptID] [int]  NOT NULL ,
[Name] [nvarchar] (50)  NULL ,
[Description] [ntext]  NULL
)
AS 

BEGIN
DECLARE @ROWSADDED INT
DECLARE @TMP TABLE(
[PDeptID] [int] NULL ,
[DeptID] [int]  NOT NULL ,
[Name] [nvarchar] (50)  NULL ,
[Description] [ntext]  NULL ,
PROCESSED TINYINT DEFAULT 0

)

INSERT  @TMP SELECT PDeptID,DeptID,[Name],[Description],0 FROM UM_DPTS WHERE DeptID=@DeptID
SELECT @ROWSADDED=@@ROWCOUNT

WHILE @ROWSADDED>0
BEGIN
UPDATE @TMP SET PROCESSED=1 WHERE PROCESSED=0

INSERT @TMP SELECT A.PDeptID,A.DeptID,A.[Name],A.[Description],0
FROM UM_DPTS A INNER JOIN @TMP B
ON A.PDeptID=B.DeptID WHERE B.PROCESSED=1
SELECT @ROWSADDED=@@ROWCOUNT

UPDATE @TMP SET PROCESSED=2 WHERE PROCESSED=1
END

INSERT  @RET_UM_DPTS
SELECT PDeptID,DeptID,[Name],[Description] FROM @TMP
RETURN
END

#39楼 得分:0回复于:2008-05-08 14:59:58
http://blog.csdn.net/xqzl/archive/2008/04/25/2326923.aspx
  • tf用户头像
  • tf
  • (菜鸟)
  • 等 级:
#40楼 得分:0回复于:2008-05-08 16:45:25
select * from table start with id=1 connect by prior pid=id where id not in (select pid from table )
#41楼 得分:0回复于:2008-05-09 08:10:32
MARK
#42楼 得分:0回复于:2008-05-09 12:33:15
mark
#43楼 得分:0回复于:2008-05-09 15:45:36
引用 14 楼 fuanwei 的回复:
SQL codedrop table tb
create table tb(id int,parentid int,sname varchar(10))
insert into tb select 1 , -1    ,    '根节点'
insert into tb select 2 ,  1    ,    '节点1'
insert into tb select 3 ,  1    ,    '节点2'
insert into tb select 4 ,  2    ,    '节点3'
insert into tb select 5 ,  2    ,    '节点4'
insert into tb select 6 ,  3    ,    '节点5'
insert into tb select 7 ,  3  …

应该是5,7吧
#44楼 得分:0回复于:2008-05-09 16:03:22
  select id ,parentid,sname from (
  SELECT level,id,parentid,sname,connect_by_isleaf as leaf
  from t
  start with id=3
  connect by parentid = prior id
  ) where leaf=1
#45楼 得分:0回复于:2008-05-09 22:00:25
好贴。
#46楼 得分:0回复于:2008-05-10 11:44:12
create table tb(id int,parentid int,sname varchar(10))
insert into tb select 1 , -1    ,    '根节点'
insert into tb select 2 ,  1    ,    '节点1'
insert into tb select 3 ,  1    ,    '节点2'
insert into tb select 4 ,  2    ,    '节点3'
insert into tb select 5 ,  2    ,    '节点4'
insert into tb select 6 ,  3    ,    '节点5'
insert into tb select 7 ,  3    ,    '节点6'
insert into tb select 7 ,  6    ,    '节点7'
go

alter FUNCTION f_Cid(@ID int)
RETURNS @t_Level TABLE(ID int,Level int)
AS
BEGIN
    DECLARE @Level int
    SET @Level=1
    INSERT @t_Level SELECT @ID,@Level
    WHILE @@ROWCOUNT>0
    BEGIN
        SET @Level=@Level+1
        INSERT @t_Level SELECT a.ID,@Level
        FROM tb a,@t_Level b
        WHERE a.parentID=b.ID
            AND b.Level=@Level-1
    END
    delete a from  @t_level a
    where exists(select 1 from @t_level where a.level <level)
    RETURN
END
GO

select a.*
from f_cid(3) b ,tb a
where b.id=a.id


go
drop table tb
drop function f_cid

有理
  • D4444用户头像
  • D4444
  • (随风)
  • 等 级:
#47楼 得分:0回复于:2008-05-10 18:02:00
tree节点问题
#48楼 得分:0回复于:2008-05-10 19:31:58
云呀,,,
#49楼 得分:0回复于:2008-05-10 20:48:29
学习了,不错~~~
#50楼 得分:0回复于:2008-05-10 23:37:52
用得着这么复杂吗?使用自身连接不就可以了。