2

I am trying to create a loop that when given a part id, it will search a table of assembly parts and put all the parts into the return table. I.e. I want to explode the parts from a single part id.

It needs to be recursive because Part 1 may have parts 2, 3, 4, 5; part 3 is an assembly item with parts 9, 10; part 10 is an assembly item with parts 11, 23, 34, 31; part 11 is an assembly item with parts 23, 24.

Database is SQL Server.

I set up some sample date here: http://sqlfiddle.com/#!9/f3cc4f

I'm expecting the results:

part, level
1,    0
2,    1
3,    1
4,    1
9,    2
10,   2
11,   3
23,   3
24,   3

Below is the code I came up with. I'm hitting a Max Recursion error, even with the sample data that is only a few level. My full dataset should go no more than 15 levels. Clearly something isn't set up correctly, and I think CTE might work better.

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

    DECLARE @chkParts table ([id] int identity(1,1), [PID] int, [level] int)

    INSERT INTO @parts_list VALUES (@source_part_id, @level)

    SET @level += 1

    INSERT INTO @chkParts
        SELECT [Comp_PartID], @level FROM /*visuser.[EN_BOM]*/ [Assemblies] WHERE [PartID] /*[Assembly_Part_ID]*/ = @source_part_id

    SELECT @max = COUNT(*) FROM @chkParts
    WHILE @cnt <= @max
    BEGIN
        SELECT @id = [id], @PID = [PID], @Plvl = [level] FROM @chkParts WHERE [id] = @cnt
        INSERT INTO @parts_list
            SELECT * FROM [fn_getParts](@PID, @Plvl)
        SET @cnt += 1
    END

    RETURN
END

Here is sample data:

CREATE TABLE Assemblies (
  PartID int NOT NULL,
  Comp_PartID int NOT NULL
);
  
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);
5
  • There are lots of tutorials out there on building recursive CTE's - I recommend having a read.
    – Dale K
    Commented Jul 8, 2020 at 0:08
  • Your expected results don't include 5 & 6, but your sample data shows (1, 5), (1, 6), i.e. PartID 1 does include 5 & 6.
    – Dale K
    Commented Jul 8, 2020 at 7:25
  • @DaleK You're right, 5 and 6 should be included, I missed that. As for parts 10 and 11 both linking to 23 & 24, I would want to include them both because I would need 2 of each of those parts to complete the assembly.
    – Dizzy49
    Commented Jul 8, 2020 at 7:56
  • Do you want to return duplicate parts? Or a list of part and a count next to them? And do you really need the level?
    – Dale K
    Commented Jul 8, 2020 at 7:58
  • 1
    @DaleK Yes, I know how to accept answers. Many of my recent questions just don't have an answer. A few had a fix in the comments.
    – Dizzy49
    Commented Jul 8, 2020 at 18:17

1 Answer 1

4

The following produces results which match your described logic, but are not the same as you are expecting. Maybe your logic needs a tweak?

declare @source_part_id int = 1, @level int = 0;

with cte (part, [level])
as (
  select @source_part_id part, @level [level]
  union all
  select Comp_PartID, [level]+1
  from Assemblies A
  inner join cte C on C.Part = A.PartID
)
select part, [level]
from cte
order by part, [level];

Returns:

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
7
  • Yeah, it's pulling all of the parts, not just the parts associated with part passed in, and then recursing through only those parts.
    – Dizzy49
    Commented Jul 8, 2020 at 2:28
  • Ok, now that I'm awake I've reviewed my data, and your output and that is correct. Thank you and I apologize for being a PITA.
    – Dizzy49
    Commented Jul 8, 2020 at 14:00
  • I'm running it on my actual data and I'm getting Types don't match between the anchor and the recursive part in column "part" of recursive query "cte". error at inner join cte C on C.Part = A.PartID. comp_part_id and Assembly_Part_ID are both bigint in the table declaration
    – Dizzy49
    Commented Jul 8, 2020 at 19:58
  • 1
    @Dizzy49 that means you table definition must be wrong i.e. one of the columns is not an int as shown.
    – Dale K
    Commented Jul 8, 2020 at 22:08
  • 1
    Good news, got it working. Bad news, the data is not entered/structured as it should be, so I ended up with 1.9m rows instead of the 2200 expected. Thanks for your help!
    – Dizzy49
    Commented Jul 9, 2020 at 6:44

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.