我有一个包含列和数据的表格如下:
Table1
ID Name PID
A1 Apple P1
B1 Book A1
B2 Brook A1
C1 Cat B1
C2 Cook B1
C3 Car B1
D1 Dog B2
D2 Doll B2
E1 Egg C1
我希望结果如下:
ID Name Depth
B1 Apple\Book 2
C1 Apple\Book\Cat 3
E1 Apple\Book\Cat\Egg 4
C2 Apple\Book\Cook 3
C3 Apple\Book\Car 3
B2 Apple\Brook 2
D1 Apple\Brook\Dog 3
D2 Apple\Brook\Doll 3
如果该行的PID
等于父行的ID
,则该行是另一行的子项。
Apple是基地。所以第一个陈述就像是:
Select ID, Name, 2 from Table1 where PID=(select ID from Table1 where Name='Apple');
我目前的解决方案是创建大量视图并将所有类似的语句保存到视图中并将它们组合在一起。但我不希望这样。我想在1个select语句中完成它.A
答案 0 :(得分:2)
我不知道是否有一种优雅的方式来获得您列出的确切顺序,但这是一种带有递归CTE的方法:
;WITH cte AS
(
SELECT ID, Name, Depth = 1
FROM dbo.Table1
WHERE Name = 'Apple'
UNION ALL
SELECT t.ID, t.Name, Depth = cte.Depth + 1
FROM cte
INNER JOIN dbo.Table1 AS t
ON t.PID = cte.ID
)
SELECT ID, Name, Depth
FROM cte
WHERE Depth > 1;
答案 1 :(得分:1)
declare @Table1 table
(
ID varchar(2),
Name varchar(10),
PID varchar(2)
)
insert into @Table1 values
('A1', 'Apple', 'P1'),
('B1', 'Book', 'A1'),
('B2', 'Brook', 'A1'),
('C1', 'Cat', 'B1'),
('C2', 'Cook', 'B1'),
('C3', 'Car', 'B1'),
('D1', 'Dog', 'B2'),
('D2', 'Doll', 'B2'),
('E1', 'Egg', 'C1')
;with C as
(
select T.ID,
cast(T.Name as varchar(max)) as Name,
1 as Depth
from @Table1 as T
where T.Name = 'Apple'
union all
select T.ID,
cast(C.Name+'\'+T.Name as varchar(max)),
C.Depth + 1
from @Table1 as T
inner join C
on T.PID = C.ID
)
select C.ID,
C.Name,
C.Depth
from C
where C.Depth > 1
order by C.Name
编辑没有Apple。
;with C as
(
select T.ID,
cast(T.Name as varchar(max)) as Name,
1 as Depth
from @Table1 as T
inner join @Table1 as TP
on T.PID = TP.ID
where TP.Name = 'Apple'
union all
select T.ID,
cast(C.Name+'\'+T.Name as varchar(max)),
C.Depth + 1
from @Table1 as T
inner join C
on T.PID = C.ID
)
select C.ID,
C.Name,
C.Depth
from C
order by C.Name
答案 2 :(得分:0)
这是我在PostgreSQL上提出的查询。我没有SQL Server,所以我无法测试,但谷歌让我相信这个查询结构也适用于SQL Server。
SELECT t1.*, (
WITH q AS (
SELECT t2.*
FROM Table1 AS t2
WHERE t2.ID = t1.ID
OR (t1.ID IS NULL AND t2.ID IS NULL)
UNION ALL
SELECT t3.*
FROM Table1 AS t3
JOIN q
ON t3.ID = q.PID
AND t3.ID <> 'P1'
-- 'P1' on the above line is the "sentinel" value you want to
-- stop traversing at. Remove the AND clause altogether if you
-- want to traverse up to the ultimate root record.
)
SELECT COUNT(q.ID)
FROM q
) AS depth
FROM Table1 AS t1;
这是在PostgreSQL上运行的示例。请注意,PostgreSQL在声明引用自身的公用表表达式时需要WITH RECURSIVE
。这和示例数据是两个查询之间的唯一区别:
$ WITH Table1(ID, Name, PID) AS (VALUES
$ ('A1', 'Apple', 'P1'),
$ ('B1', 'Book', 'A1'),
$ ('B2', 'Brook', 'A1'),
$ ('C1', 'Cat', 'B1'),
$ ('C2', 'Cook', 'B1'),
$ ('C3', 'Car', 'B1'),
$ ('D1', 'Dog', 'B2'),
$ ('D2', 'Doll', 'B2'),
$ ('E1', 'Egg', 'C1')
$ )
$ SELECT t1.*, (
$ WITH RECURSIVE q AS (
$ SELECT t2.*
$ FROM Table1 AS t2
$ WHERE t2.ID = t1.ID
$ OR (t1.ID IS NULL AND t2.ID IS NULL)
$
$ UNION ALL
$
$ SELECT t3.*
$ FROM Table1 AS t3
$ JOIN q
$ ON t3.ID = q.PID
$ AND t3.ID <> 'P1'
$ )
$ SELECT COUNT(q.ID)
$ FROM q
$ ) AS depth
$ FROM Table1 AS t1;
id | name | pid | depth
----+-------+-----+-------
A1 | Apple | P1 | 1
B1 | Book | A1 | 2
B2 | Brook | A1 | 2
C1 | Cat | B1 | 3
C2 | Cook | B1 | 3
C3 | Car | B1 | 3
D1 | Dog | B2 | 3
D2 | Doll | B2 | 3
E1 | Egg | C1 | 4
(9 rows)