如何在递归函数的循环中使用#tmp Table
How to use #tmp Table in Loop in Recursive Function
我正在尝试创建一个循环,当给定零件 ID 时,它会搜索 table 个装配零件并将所有零件展开到一个大列表中。
需要递归,因为123部分可能有1、2、3、4、5部分,4、5部分也是装配项。
我以为我想出了一些非常好的东西,并且很容易 returns 每个项目的零件 ID 和零件级别。然后我发现我不能使用 temp tables,所以它会降低我的循环。
我可以用什么代替临时 table 来给我同样的功能?
CREATE FUNCTION [dbo].[fn_getParts] (
@source_part_id int
, @level int
)
RETURNS @parts_list TABLE (
[part] int NOT NULL,
[level] int NOT NULL
)
AS
BEGIN
DECLARE
@max int = 0,
@cnt int = 0,
@PID int = 0,
@Plvl int = 0,
@id int = 0
INSERT INTO @parts_list VALUES (@source_part_id, @level)
SET @level += 1
SELECT [Comp_Part_ID] AS [PID], @level AS [level]
INTO #chkParts
FROM [assemblies]
WHERE [Assy_PID] = @source_part_id
SELECT @max = COUNT(*) FROM #chkParts
WHILE @cnt <= @max
BEGIN
SELECT @PID = [PID], @Plvl = [level] FROM #chkParts
INSERT INTO @parts_list
SELECT * FROM [fn_getParts](@PID, @Plvl)
SET @cnt += 1
END
RETURN
END
下面是一些示例数据:
CREATE TABLE [Assemblies] (
[PartID] int,
[Comp_PartID] int
)
INSERT INTO [Assemblies] VALUES
(1,2),
(1,3),
(1,4),
(1,5),
(1,6),
(3,9),
(3,10),
(10,11),
(10,23),
(10,24),
(10,31),
(11,24),
(11,23)
如果我输入 SELECT * FROM [fn_getParts](1,0)
,我会得到以下结果:
part,level
1,0
2,1
3,1
4,1
9,2
10,2
11,3
23,3
24,3
通过将内联 Table 值函数包装在递归 CTE 周围,可以稍微简化代码,例如:
create function dbo.fn_getParts (
@source_part_id int
)
returns table as return (
with PartsHierarchy as (
select @source_part_id as part, 0 as level
union all
select Comp_PartID, 1 + level
from Assemblies
join PartsHierarchy on part = PartID
)
select part, level
from PartsHierarchy
);
然后,为不同的部件号调用它...
select * from dbo.fn_getParts(1);
part level
---- ----
1 0
2 1
3 1
4 1
5 1
6 1
9 2
10 2
11 3
23 3
24 3
31 3
24 4
23 4
select * from dbo.fn_getParts(10);
part level
---- -----
10 0
11 1
23 1
24 1
31 1
24 2
23 2
select * from dbo.fn_getParts(11);
part level
---- -----
11 0
24 1
23 1
我正在尝试创建一个循环,当给定零件 ID 时,它会搜索 table 个装配零件并将所有零件展开到一个大列表中。
需要递归,因为123部分可能有1、2、3、4、5部分,4、5部分也是装配项。 我以为我想出了一些非常好的东西,并且很容易 returns 每个项目的零件 ID 和零件级别。然后我发现我不能使用 temp tables,所以它会降低我的循环。
我可以用什么代替临时 table 来给我同样的功能?
CREATE FUNCTION [dbo].[fn_getParts] (
@source_part_id int
, @level int
)
RETURNS @parts_list TABLE (
[part] int NOT NULL,
[level] int NOT NULL
)
AS
BEGIN
DECLARE
@max int = 0,
@cnt int = 0,
@PID int = 0,
@Plvl int = 0,
@id int = 0
INSERT INTO @parts_list VALUES (@source_part_id, @level)
SET @level += 1
SELECT [Comp_Part_ID] AS [PID], @level AS [level]
INTO #chkParts
FROM [assemblies]
WHERE [Assy_PID] = @source_part_id
SELECT @max = COUNT(*) FROM #chkParts
WHILE @cnt <= @max
BEGIN
SELECT @PID = [PID], @Plvl = [level] FROM #chkParts
INSERT INTO @parts_list
SELECT * FROM [fn_getParts](@PID, @Plvl)
SET @cnt += 1
END
RETURN
END
下面是一些示例数据:
CREATE TABLE [Assemblies] (
[PartID] int,
[Comp_PartID] int
)
INSERT INTO [Assemblies] VALUES
(1,2),
(1,3),
(1,4),
(1,5),
(1,6),
(3,9),
(3,10),
(10,11),
(10,23),
(10,24),
(10,31),
(11,24),
(11,23)
如果我输入 SELECT * FROM [fn_getParts](1,0)
,我会得到以下结果:
part,level
1,0
2,1
3,1
4,1
9,2
10,2
11,3
23,3
24,3
通过将内联 Table 值函数包装在递归 CTE 周围,可以稍微简化代码,例如:
create function dbo.fn_getParts (
@source_part_id int
)
returns table as return (
with PartsHierarchy as (
select @source_part_id as part, 0 as level
union all
select Comp_PartID, 1 + level
from Assemblies
join PartsHierarchy on part = PartID
)
select part, level
from PartsHierarchy
);
然后,为不同的部件号调用它...
select * from dbo.fn_getParts(1);
part level
---- ----
1 0
2 1
3 1
4 1
5 1
6 1
9 2
10 2
11 3
23 3
24 3
31 3
24 4
23 4
select * from dbo.fn_getParts(10);
part level
---- -----
10 0
11 1
23 1
24 1
31 1
24 2
23 2
select * from dbo.fn_getParts(11);
part level
---- -----
11 0
24 1
23 1