Solved

Need to Add Levels for Indented BOM Explosion Dataset Using SQL

Posted on 2009-07-08
15
1,342 Views
Last Modified: 2012-05-07
Hello Experts!

As you can see from the attached file containing example data and the desired output, not only are there many levels of parent/child records, but you also have to make sure you're accessing the latest revision of the part number where the effectivedate <= today's date.

A partial BOM explosion would go like this (Partnum, Revisionnum):

TOP LEVEL 0:  NC006000    C
      LEVEL 1:  NC00M021    6  (NO FURTHER BOM EXPLOSION ON THIS PART NUMBER)
        LEVEL 1:  NC00M022    5  (NO FURTHER BOM EXPLOSION ON THIS PART NUMBER)
      LEVEL 1:  NC006303    B
            LEVEL 2:  NC006301   B
            LEVEL 2:  NC006140   K
                  LEVEL 3:  NC006141   K
                  ...and so on.

I only need to perform this explosion for one part number at a time, in this case NC006000.  This will always be a hardcoded part number because this query is not to be run by anybody but a programmer at this point.

I have very little SQL experience but am a good fast learner.  I've been scouring many different books, forums, web sites, and any other source I can get my paws on for an answer for this.  I've seen some good answers on EE but they usually are based on tables that (conveniently!) include the BOM levels.  I somehow have to count them as I go and that is just over my head!  

I found a snippet of recursive code that I've been playing with but have no idea how to add levels.  Help???


WITH RPL AS (SELECT     PARTMTL.PARTNUM, PARTMTL.MTLPARTNUM, PARTMTL.QTYPER

                                FROM         dbo.partmtl

                                WHERE     (PARTMTL.PARTNUM = 'NC006000')

                                UNION ALL

                                SELECT     CHILD.partnum, CHILD.mtlpartnum, CHILD.qtyper

                                FROM         RPL AS PARENT INNER JOIN

                                                      dbo.partmtl AS CHILD ON PARENT.MTLPARTNUM = CHILD.partnum)

    SELECT DISTINCT PARTNUM, MTLPARTNUM, QTYPER

     FROM         RPL AS RPL_1

     ORDER BY PARTNUM, MTLPARTNUM, QTYPER

Open in new window

BOM-Data-Output.txt
0
Comment
Question by:MTaft
  • 7
  • 7
15 Comments
 
LVL 1

Author Comment

by:MTaft
Comment Utility
The deepest level would be 8.
0
 
LVL 51

Expert Comment

by:Mark Wills
Comment Utility
Sounds like a CTE query to me... Will have a look at your txt file and get back to you...

Any chance of getting the three tables as spreadsheets ?
0
 
LVL 1

Author Comment

by:MTaft
Comment Utility
Sure, I've just stripped out the fields you need for this query.  Each table is on a different Excel tab.  They are all linked by company ("NC") and partnum.
Sample-Data-for-BOM.xlsx
0
 
LVL 51

Expert Comment

by:Mark Wills
Comment Utility
Thanks for that, was getting very caught up on mtlpartnum existing in parts table and then the revnum not matching...
0
 
LVL 1

Author Comment

by:MTaft
Comment Utility
I can't tell you how much I appreciate your help.  I've been struggling for days on this, and I am an IT department of one at the little company I work for.  Although I've been programming for 10+ years in Progress, I've never had to do much more than a basic select statement in SQL.  Do you have any recommendations for books or other resources that go into good concise detail on the more complex SQL logic that's possible?
0
 
LVL 51

Expert Comment

by:Mark Wills
Comment Utility
Have played with Progress. Bit different :)  As to best books, there are a few, suggest looking at MS Press as a starting point, and then there is always EE :)

Right...

First challenge was to get the current versions. Easiest way was to create a view on the PARTREV table so that every PARTNUM has only 1 REVISIONNUM.

A VIEW is like a "virtual" table. It is created just the once, and can be accessed much like any table there after.

The second step was to get the BOM exploding the correct way. We use a CTE query to do this - basically a (recursive) query that allows you to select back on itself.

Have a look below...

-- step 1 and a once off task, once run, then do not have to worry about creating the view again.

-- a view is like a virtual table - it is resolved at runtime. This one is giving us the current revisionnum as at "today"
 

create view vw_PARTREV as

Select P.PARTNUM, P.REVISIONNUM, P.EFFECTIVEDATE

from PARTREV P

inner join (select partnum, max(effectivedate) as effectivedate from partrev where effectivedate <= getdate() group by partnum) B on B.partnum = P.partnum and B.effectivedate = P.effectivedate

GO
 

-- just to check, have a look
 

select * from vw_PARTREV
 

-- now the real query...

-- a recursive query - must be the first command in a batch - easiest way is to prefix it with a semicolon

-- basic syntax is :  with cte as (select stuff) select * from cte 
 

;with CTE_BOM as

(

     select 0 as level, 000 as seq, part.partnum as parent, part.partnum, revisionnum , description, convert(decimal(18,8),0) as qty, ium, convert(varchar(800),'0') as path  from part inner join vw_partrev on part.partnum=vw_partrev.partnum

     where part.partnum = 'NC006000'
 

     union all
 

     select B.level+1, convert(int,M.mtlseq), M.partnum, M.mtlpartnum, R.revisionnum, P.description, convert(decimal(18,8),M.qtyper), P.IUM, convert(varchar(800),b.path+','+convert(varchar(10),M.mtlseq))

     from CTE_BOM B

     inner join PART P on P.partnum = B.partnum

     inner join vw_PARTREV R on R.partnum = B.partnum 

     inner join PARTMTL M on M.partnum = R.partnum and M.revisionnum = R.revisionnum

)

select *,replicate('....',level)+partnum as tree from CTE_BOM

Order by level,parent,seq,partnum     -- or order by path to get indented BOM

Open in new window

0
 
LVL 1

Author Comment

by:MTaft
Comment Utility
What a wonderful explanation.  Thank you!

Now, when I try to run it as a query, it comes up with this error:

'CREATE VIEW' must be the first statement in a query batch.

And except for the comments, it is, so that doesn't make any sense to me.
0
How to improve team productivity

Quip adds documents, spreadsheets, and tasklists to your Slack experience
- Elevate ideas to Quip docs
- Share Quip docs in Slack
- Get notified of changes to your docs
- Available on iOS/Android/Desktop/Web
- Online/Offline

 
LVL 51

Expert Comment

by:Mark Wills
Comment Utility
open a new QUERY window in SSMS (shortcut key = ctrl+N), copy just the create view lines 4 through to 7 and press execute (shortcut key = F5)

You can also highlight just the required code and press F5 to execute just the highlighted (selected) code.
0
 
LVL 1

Author Comment

by:MTaft
Comment Utility
I see.. so when you say it's a once-only deal, it actually created something permanent in the db.  

The only two things that is not quite right with this breathtakingly lovely piece of code (and it is entirely my fault for not specifying) is that the revisionnum must be the revision num of the child part number, and the description must be the description of the child part number.  I'm going to fiddle with it to see if I can get it because darn it, I should be able to figure SOMETHING out on my own!
0
 
LVL 51

Expert Comment

by:Mark Wills
Comment Utility
Ah yes, picking it up in the wrong sequence...


;with CTE_BOM as
(
     select 0 as level, 000 as seq, part.partnum as parent, part.partnum, revisionnum , description, convert(decimal(18,8),0) as qty, ium, convert(varchar(800),'0') as path  from part inner join vw_partrev on part.partnum=vw_partrev.partnum
     where part.partnum = 'NC006000'

     union all

     select B.level+1, convert(int,M.mtlseq), M.partnum, M.mtlpartnum, R.revisionnum, P.description, convert(decimal(18,8),M.qtyper), P.IUM, convert(varchar(800),b.path+','+convert(varchar(10),M.mtlseq))
     from CTE_BOM B
     inner join PARTMTL M on M.partnum = B.partnum
     inner join vw_PARTREV R on R.partnum = B.partnum and R.revisionnum = M.revisionnum  
     inner join PART P on P.partnum = M.mtlpartnum
)
select *,replicate('....',level)+partnum as tree from CTE_BOM
Order by level,parent,seq,partnum     -- or order by path to get indented BOM

0
 
LVL 1

Author Comment

by:MTaft
Comment Utility
Almost.... that fixed the description but not the revision level.  Still showing the revision level of the parent part number.
0
 
LVL 51

Accepted Solution

by:
Mark Wills earned 500 total points
Comment Utility
OK. We might have a small challenge...

We must have the revision number for the Parent to get the correct entry from PARTMTL...

So, maybe we can pick up both, and then you can use the most appropriate :


;with BOM as
(
     select 0 as level, 000 as seq, part.partnum as parent, revisionnum as P_revisionnum, part.partnum, revisionnum as C_revisionnum , description, convert(decimal(18,8),0) as qty, ium, convert(varchar(800),'0') as path  from part inner join vw_partrev on part.partnum=vw_partrev.partnum
     where part.partnum = 'NC006000'

     union all

     select B.level+1, convert(int,M.mtlseq), M.partnum,  R.revisionnum, M.mtlpartnum, CR.revisionnum, P.description, convert(decimal(18,8),M.qtyper), P.IUM, convert(varchar(800),b.path+','+convert(varchar(10),M.mtlseq))
     from BOM B
     inner join PARTMTL M on M.partnum = B.partnum
     inner join vw_PARTREV R on R.partnum = B.partnum and M.revisionnum = R.revisionnum
     inner join PART P on P.partnum = M.mtlpartnum
     inner join vw_PARTREV CR on CR.partnum = P.partnum  
)
select *,replicate('....',level)+partnum as tree from BOM
Order by level,parent,seq,partnum     -- or order by path to get indented BOM



0
 
LVL 1

Author Closing Comment

by:MTaft
Comment Utility
Thank you so much!  This is EXACTLY what I needed, and you explained it very well.  I will definitely be able to re-use and modify this logic and know what it means.  Thank you again!
0
 
LVL 51

Expert Comment

by:Mark Wills
Comment Utility
A pleasure working with you and very happy to have been of assistance...
0

Featured Post

6 Surprising Benefits of Threat Intelligence

All sorts of threat intelligence is available on the web. Intelligence you can learn from, and use to anticipate and prepare for future attacks.

Join & Write a Comment

JSON is being used more and more, besides XML, and you surely wanted to parse the data out into SQL instead of doing it in some Javascript. The below function in SQL Server can do the job for you, returning a quick table with the parsed data.
Slowly Changing Dimension Transformation component in data task flow is very useful for us to manage and control how data changes in SSIS.
Via a live example, show how to extract information from SQL Server on Database, Connection and Server properties
Viewers will learn how to use the UPDATE and DELETE statements to change or remove existing data from their tables. Make a table: Update a specific column given a specific row using the UPDATE statement: Remove a set of values using the DELETE s…

772 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

14 Experts available now in Live!

Get 1:1 Help Now