SQL Recursive CTE Lookup in Hierarchy to get a Part Only Flat BOM

19 views Asked by At

I am trying to create a part only flat level Puchase/Manufacturing BOM from a Hierarchal Engineering BOM. the Database is set up with a PARTMASER table the lists all partnumberss and a BOMLEGER table that has the PARENT, CHILD columns for all assemblies. I am using the following code to get my flat BOM

WITH cteBuildPath AS
   (
   --=== This is the "anchor" part of the recursive CTE.
     -- The only thing it does is load the Root Node.
      SELECT ROOT.PARENT_PARTMASTER_CODE, ROOT.CHILD_PARTMASTER_CODE, ROOT.BOMLEGER_QTY
       FROM BOMLEGER ROOT
       WHERE ROOT.PARENT_PARTMASTER_CODE LIKE '%10550-03A%'--The Root Node
    UNION ALL
     --==== This is the "recursive" part of the CTE that adds 1 for each level
     -- and concatenates each level of EmployeeID's to the SortPath column.
      SELECT 
            PARENT.PARENT_PARTMASTER_CODE, 
            --CHILD.PARENT_PARTMASTER_CODE as SUBPARENT,
            CHILD.CHILD_PARTMASTER_CODE, 
            CONVERT(decimal(6,2),PARENT.BOMLEGER_QTY*CHILD.BOMLEGER_QTY)
       FROM 
            cteBuildPath PARENT, 
            BOMLEGER CHILD
       WHERE PARENT.CHILD_PARTMASTER_CODE = CHILD.PARENT_PARTMASTER_CODE
   )
   --=== This final SELECT/INTO creates the Node # in the same order as a
     -- push-stack would.
SELECT PARENT_PARTMASTER_CODE AS PARENT, 
--SUBPARENT,
CHILD_PARTMASTER_CODE AS CHILD, 
SUM(BOMLEGER_QTY) AS "Total QTY"

 FROM cteBuildPath
  GROUP BY PARENT_PARTMASTER_CODE, CHILD_PARTMASTER_CODE
  ORDER BY PARENT_PARTMASTER_CODE, CHILD_PARTMASTER_CODE;

and I get the result

PARENT CHILD Total QTY
10550-03A CMP-0000003 2.00
10550-03A HARD-0000816 8.00
10550-03A HARD-0000817 8.00
10550-03A HARD-0000834 24.00
10550-03A HARD-0000835 24.00
10550-03A HARD-0000840 24.00
10550-03A HARD-0000866 6.00
10550-03A HARD-0000868 8.00
10550-03A HARD-0000872 4.00
10550-03A HARD-0000874 4.00
10550-03A HARD-0001047 4.00
10550-03A HARD-0001103 8.00
10550-03A MECH-0001409 4.00
10550-03A PLT-0000131 2.00
10550-03A PLT-0000132 1.00
10550-03A PLT-0000133 4.00
10550-03A PLT-0000134 1.00
10550-03A PLT-0000135 1.00
10550-03A PLT-0000136 1.00
10550-03A PLT-0000137 1.00
10550-03A PLT-0000138 4.00
10550-03A PLT-0000139 2.00
10550-03A PLUMB-0001378 2.00
10550-03A PUR-0000003 4.00
10550-03A PUR-0000004 1.00
10550-03A PUR-0000005 4.00
10550-03A PUR-0000006 2.00
10550-03A STR-0000138 4.00
10550-03A STR-0000139 2.00
10550-03A STR-0000140 4.00
10550-03A STR-0000141 4.00
10550-03A STR-0000142 1.00
10550-03A STR-0000143 1.00
10550-03A STR-0000144 2.00
10550-03A STR-0000145 1.00
10550-03A STR-0000146 1.00
10550-03A STR-0000147 1.00
10550-03A STR-0000148 2.00
10550-03A STR-0000149 2.00
10550-03A STR-0000150 2.00
10550-03A STR-0000151 2.00
10550-03A STR-0000152 1.00
10550-03A STR-0000153 2.00
10550-03A STR-0000154 2.00
10550-03A STR-0000155 4.00
10550-03A STR-0000156 2.00
10550-03A SUB-0000018 1.00
10550-03A WLD-0000120 1.00
10550-03A WLD-0000122 1.00
10550-03A WLD-0000123 1.00
10550-03A WLD-0000124 1.00
10550-03A WLD-0000125 2.00

The issue is I am getting all the mid sub-assemblies in my result and I don't want them. So the SUB-0000018 is a midlevel Subassembly with children so since the Children are in the output I dont want the Subassembly.

1

There are 1 answers

0
Charlieface On BEST ANSWER

You can just add a NOT EXISTS to the final SELECT to check if it's the bottom level part.

WITH cteBuildPath AS
(
   --=== This is the "anchor" part of the recursive CTE.
     -- The only thing it does is load the Root Node.
      SELECT
        ROOT.PARENT_PARTMASTER_CODE,
        ROOT.CHILD_PARTMASTER_CODE,
        ROOT.BOMLEGER_QTY
      FROM BOMLEGER ROOT
      WHERE ROOT.PARENT_PARTMASTER_CODE LIKE '%10550-03A%'--The Root Node

    UNION ALL

     --==== This is the "recursive" part of the CTE that adds 1 for each level
     -- and concatenates each level of EmployeeID's to the SortPath column.
    SELECT 
        PARENT.PARENT_PARTMASTER_CODE, 
        CHILD.CHILD_PARTMASTER_CODE,
        CONVERT(decimal(6,2), PARENT.BOMLEGER_QTY * CHILD.BOMLEGER_QTY)
    FROM 
      cteBuildPath PARENT
    JOIN BOMLEGER CHILD
        ON PARENT.CHILD_PARTMASTER_CODE = CHILD.PARENT_PARTMASTER_CODE
)
   --=== This final SELECT/INTO creates the Node # in the same order as a
     -- push-stack would.
SELECT
  PARENT_PARTMASTER_CODE AS PARENT, 
  CHILD_PARTMASTER_CODE AS CHILD, 
  SUM(BOMLEGER_QTY) AS "Total QTY"
FROM cteBuildPath bp
WHERE NOT EXISTS (SELECT 1
    FROM BOMLEDGER_ROOT child
    WHERE child.PARENT_PARTMASTER_CODE = bp.CHILD_PARTMASTER_CODE
)
GROUP BY
  PARENT_PARTMASTER_CODE,
  CHILD_PARTMASTER_CODE
ORDER BY
  PARENT_PARTMASTER_CODE,
  CHILD_PARTMASTER_CODE;