是的,可以使用递归 CTE 来完成。
USE tempdb
GO
CREATE TABLE files
(
[file_id] int PRIMARY KEY,
[file_name] varchar(128) NOT NULL
);
INSERT INTO files VALUES
(1, 'File 1'),
(2, 'File 2'),
(3, 'File 3'),
(4, 'File 4'),
(5, 'File 5'),
(6, 'File 6'),
(7, 'File 7'),
(8, 'File 8'),
(9, 'File 9'),
(10, 'File 10');
CREATE TABLE [references]
(
parent_file_id int NOT NULL,
child_file_id int NOT NULL,
PRIMARY KEY (child_file_id)
);
INSERT INTO [references] VALUES
(1, 2),
(1, 3),
(1, 4),
(1, 5),
(5, 6),
(5, 7),
(5, 8),
(8, 9),
(8, 10);
GO
CREATE FUNCTION dbo.get_file_with_path(@file_id int)
RETURNS TABLE
AS
RETURN WITH h
AS
(
SELECT
f.file_id, f.file_id as child_file_id,
f.file_name, 0 as reverse_level,
CAST( '/' + f.file_name as varchar(8000)) as path
FROM
dbo.files f
WHERE
f.file_id = @file_id
UNION ALL
SELECT
h.file_id, r.parent_file_id as child_file_id,
h.file_name, h.reverse_level + 1 as reverse_level,
CAST('/' + f.file_name + h.path as varchar(8000)) as path
FROM
h
INNER JOIN [references] r
ON h.child_file_id = r.child_file_id
INNER JOIN dbo.files f
ON f.file_id = r.parent_file_id
)
SELECT TOP(1) h.file_id, h.file_name, h.path
FROM h
ORDER BY h.reverse_level DESC;
GO
SELECT *
FROM dbo.get_file_with_path(1)
UNION ALL
SELECT *
FROM dbo.get_file_with_path(3)
UNION ALL
SELECT *
FROM dbo.get_file_with_path(6)
UNION ALL
SELECT *
FROM dbo.get_file_with_path(10)
输出:
| file_id | file_name | path |
|---------|-----------|-------------------------------|
| 1 | File 1 | /File 1 |
| 3 | File 3 | /File 1/File 3 |
| 6 | File 6 | /File 1/File 5/File 6 |
| 10 | File 10 | /File 1/File 5/File 8/File 10 |
当你说 position
时,我假设你的意思是
path
编辑:
在cmets中回答问题,还可以创建一个表值函数,返回给定节点下的子树:
CREATE FUNCTION dbo.get_file_subtree_excluding_self(@file_id int)
RETURNS TABLE
AS RETURN
WITH h AS
(
SELECT r.parent_file_id, r.child_file_id
FROM [references] r
WHERE r.parent_file_id = @file_id
UNION ALL
SELECT r.parent_file_id, r.child_file_id
FROM
h INNER JOIN [references] r
ON h.child_file_id = r.parent_file_id
)
SELECT h.child_file_id as [file_id]
FROM h
GO
SELECT * FROM dbo.get_file_subtree_excluding_self(5)
输出:
+---------+
| file_id |
+---------+
| 6 |
| 7 |
| 8 |
| 9 |
| 10 |
+---------+
表格references 描述了一个图表。由于主键,一个节点只能有一个父节点,但没有什么能阻止循环。例如,考虑以下数据:
+-------+--------+
| child | parent |
+-------+--------+
| 1 | 2 |
| 2 | 3 |
| 3 | 1 |
+-------+--------+
如您所见,此图上有循环。