【求教】 请问个困难问题。
create table A(aID int identity(1,1),baseid int,[name] varchar(20))
create table B(bID int identity(1,1),parentId int,childId int)
insert A
select 1,'aaa' union all
select 2,'bbb' union all
select 3,'ccc' union all
select 4,'a1' union all
select 5,'a2' union all
select 6,'b1' union all
select 7,'aa1' union all
select 8,'dsdssd'
insert B
select 1,4 union all
select 1,5 union all
select 4,7 union all
select 7,8
注:A.baseId = B.parentId
表B中的childId对应A表的Id,意思就是说A表存了所有数据,包括所以节点,而B只存有关系.
树结构如下:
---1
---4
---7
---8
---5
---2
---3
---6
现在假如获取顶层节点和第一子节点,请问怎么解决。
[最优解释]
整理一下格式加点注释
--create table A(aID int identity(1,1),baseid int,[name] varchar(20))
--create table B(bID int identity(1,1),parentId int,childId int)
--insert A
--select 1,'aaa' union all
--select 2,'bbb' union all
--select 3,'ccc' union all
--select 4,'a1' union all
--select 5,'a2' union all
--select 6,'b1' union all
--select 7,'aa1' union all
--select 8,'dsdssd'
--insert B
--select 1,4 union all
--select 1,5 union all
--select 4,7 union all
--select 7,8
WITH cte
AS ( SELECT parentId ,
childId ,
1 [LEVEL] --定义级别为顶层
FROM b
WHERE parentid = 1
UNION ALL
SELECT b.parentid ,
b.childId ,
a.[level] + 1 --计算B中的个个级别
FROM cte a
INNER JOIN B ON B.parentid = a.childId
)
--SELECT * FROM cte --这步可以看到CTE的运行结果
SELECT DISTINCT
parentid baseid
FROM cte
WHERE [LEVEL] IN ( 1, 2 ) --选择parentid列中级别为1、2的数据
UNION
SELECT DISTINCT
childId baseid
FROM cte
WHERE [LEVEL] IN ( 1 ) --选择childid列中级别为1的数据,由于为2 的时候会把7也引出来
UNION
--筛选在A中但不在B中的数据
SELECT *
FROM ( SELECT baseid
FROM A
WHERE baseid NOT IN ( SELECT parentId
FROM B
UNION
SELECT childId
FROM b )
) b
/*
baseid
-----------
1
2
3
4
5
6
(6 行受影响)
*/
[其他解释]
select * --无子顶层
from A
where aid not in (select parentid from B union select childid from B)
union all
select * --有子顶层
from A where aID in (select distinct parentId from B where not parentId in (select childid from B))
union all
select * --第一个子
from A where aID in (select distinct childId from B where parentId in (select distinct parentId from B where not parentId in (select childid from B)))
[其他解释]
SELECT *
FROM A LEFT JOIN b
ON A.baseId = B.parentId
parentid 为null的不就是顶层的咯?至于第一子节点.....你要一起查出来?那展示的结果是如何的?
[其他解释]
主要是关系都存放在B表中,parentId没有null的数据,有关系就存,没关系就没有数据。
希望显示结果1,2,3,4,5,6 顺序无所谓/
[其他解释]
想用cte来写 但是没有写出来.
[其他解释]
B表的数据是不是不全啊?cte可以啊,纯操作B表就够了.有需要再关联A表
[其他解释]
B表数据是全的,比如A表中2在B表中不存在 则说明2是顶层
[其他解释]
--create table A(aID int identity(1,1),baseid int,[name] varchar(20))
--create table B(bID int identity(1,1),parentId int,childId int)
--insert A
--select 1,'aaa' union all
--select 2,'bbb' union all
--select 3,'ccc' union all
--select 4,'a1' union all
--select 5,'a2' union all
--select 6,'b1' union all
--select 7,'aa1' union all
--select 8,'dsdssd'
--insert B
--select 1,4 union all
--select 1,5 union all
--select 4,7 union all
--select 7,8
WITH cte AS
(
SELECT parentId ,childId,1 [LEVEL]
FROM b
WHERE parentid=1
UNION ALL
SELECT b.parentid,b.childId,a.[level]+1
FROM cte a INNER JOIN B ON B.parentid=a.childId
)
--SELECT * FROM cte --把这里取消注销可以看到CTE的结果
--/*
SELECT DISTINCT parentid baseid FROM cte WHERE [LEVEL] IN (1 ,2)
UNION
select DISTINCT childId baseid FROM cte WHERE [LEVEL] IN (1 ) --由于要过滤第三层,所以这里只查询1
UNION
SELECT * FROM (
SELECT baseid
FROM A
WHERE baseid NOT IN (
SELECT parentId
FROM B
UNION
SELECT childId
FROM b
) )b
/*
baseid
-----------
1
2
3
4
5
6
(6 行受影响)
*/
[其他解释]
上面都用UNION 来取消重复值,
[其他解释]
返回层级,查找 0,1的就是
[其他解释]
先感谢了 我在看看
[其他解释]
自增id不好用吧。万一插入的顺序变了还能用?
[其他解释]
这种扩展性有点低,假如要找第3.4.5层就累死了。
[其他解释]
实际存的Guid,ID只是举例
[其他解释]
最好的方法就是一次性把整个结构弄出来,然后在where中控制取多少层。不过由于你的B表没有存够足够的数据。还是有点大工作量
[其他解释]
其实我的意思是,对于标识列,它主要是标识,其实没有多大的现实意义。如果你插入的顺序改变了。可能会有麻烦,当然我还没测试过。反正我个人不喜欢这样做。
[其他解释]
顺便在请教一个问题
cte执行过程是怎么样的啊。一直没有搞懂,所以写的乱七八糟的。
[其他解释]
该回复于2012-11-08 21:02:23被管理员删除
[其他解释]
表设计的有问题 ,应该有个总树根 然后往下了铺 。算法也简单 你现在整的是森林啊
[其他解释]
with里面的UNION all上面那个,是找出一个标准数据,比如顶层,然后下面那个就是外围表和顶层做运算,得到第二个CTE,再与外围表做运算,得到第三个CTE,再于外围表运算,一直到条件不满足位置。不过这个真要自己去体会才行。我也说不清楚。可能我表达能力不行吧
[其他解释]
基本上搞懂了 ,在消化下。感谢大家了。
[其他解释]
要我设计我也不会这么设计,一张表搞定关系和数据。
主要是用的别公司的库。
[其他解释]
这样的表设计应该在B表中不会出现A的所有数据
A的顶层节点在B中应该是无记录的。
[其他解释]
如果B表存有所有的关系,那直接操作就可以了,没那么麻烦
[其他解释]
因为A只存数据,关系都存于B
要想获得数据,必须连A了
[其他解释]
没记录可以使用0或者-1代替,主要是标识。你不存的话,我要额外和A表关联
[其他解释]
刚才试了一下你写的sql
我在优化下,看了执行计划,听夸张的。
[其他解释]
你把关系都弄好了,最后展示的时候再关联A完全可以。这样也有利于语句的执行效率
[其他解释]
有分就行
[其他解释]
没办法,要遍历。而且要去除重复值,这是在一个烂摊子上面做的东西。好不了哪里去