split BOM by reference designators

22strider

Active Member
Joined
Jun 11, 2007
Messages
311
Hello Friends

Could anyone please help figuring out macro (VBA routine) for the following?
The original spreadsheet has bill of materials (BOM) export with columns ParentItem, ChildItem, Qty and RefDesig. Following is the sample table:
ParentItem Child Item Qty RefDesig
P12345 C12345 2 R12,R23
P12345 C45678 3 C56,C45,C89
P12345 C6598 4

Entries under column RefDesig are separated by comma.
I need a macro that would read and count entries under RefDesig and enter rows one each for RefDesig and change qty from its original number to 1. And if there is no RefDesig the Qty will remain as is.
Following is the table showing expected output:
ParentItem Child Item Qty RefDesig
P12345 C12345 1 R12
P12345 C12345 1 R23
P12345 C45678 1 C56
P12345 C45678 1 C45
P12345 C45678 1 C89
P12345 C6598 4

You may notice that the row one (in the original table) has been split into two rows (because in original table it had 2 reference designators) and the row two has been split into three rows. And row three in the original table remains as is in the result table because there was no reference designator.
Thanks
Rajesh
 
hiker95,
Your code worked out wonderfully for me as well! Though I still have another dilemma that my inexperienced VBA fingers cannot dominate. Once all the reference designators are split out into rows I have some ranges that are left over (i.e., C45-C50, R32- R50). Do you have any ideas that may split these out into single reference designators?

Thanks!
 
Last edited:
Upvote 0

Excel Facts

Shade all formula cells
To shade all formula cells: Home, Find & Select, Formulas to select all formulas. Then apply a light fill color.
vdevita,

Please start you own New Post, with a new title.


In the New Post give us:

What version of Excel are you using?

Can you post the raw data worksheet, and, post the worksheet results (manually formatted by you) that you are looking for?

To post your data, you can download and install one of the following two programs:
Excel Jeanie
MrExcel HTML Maker

Or, when using Internet Explorer, just put borders around your data in Excel and copy those cells into your post.


If you are not able to give us screenshots:
You can upload your workbook to Box Net,

sensitive data scrubbed/removed/changed

mark the workbook for sharing
and provide us with a link to your workbook.



Then, send me a Private Message with a link to your New Post, and I will have a look.
 
Upvote 0
vdevita,

Thanks for the Private Message.

I checked the link, and it looks like you have already received a solution.
 
Upvote 0
Just registered because I wanted to say thank you very much, hiker95, this saved me a lot of work.

By the way, I talked with a colleague at work and wanted to add an improvement, so he did the coding. This improvement is for me, I hope it can be useful for others too.

Not only splits the designators, but also sorts them but the right way (C1, C2, C3, ... instead of C1,C10,C100,C2,C20, ...).
It also run some checks like if the quantities before and after splitting are the same.

Code:
Attribute VB_Name = "Module1"
Option Explicit


Sub SplitBOM()


' hiker95, 02/13/2012
' http://www.mrexcel.com/forum/excel-questions/613198-split-bom-reference-designators.html


Dim itemColumnIndex As Long: itemColumnIndex = 1
Dim quantityColumnIndex As Long: quantityColumnIndex = 3
Dim referenceColumnIndex As Long: referenceColumnIndex = 4
Dim rowStartIndex As Long: rowStartIndex = 2
Dim r As Long, c As Long, i As Long, maxRowIndex As Long, maxColumnIndex As Long, referenceSplit, n As Long
Dim initialQuantitySum As Long: initialQuantitySum = 0
Dim resultQuantitySum As Long: resultQuantitySum = 0
Dim hasError As Boolean: hasError = False
Dim xLen As Long
Dim xStr As String


Application.ScreenUpdating = False


' Unión de referencias por Item:
'   Recorre todas las filas desde el inicio (omitiendo la cabecera) y comprueba si la columna de cantidad
'   está vacía. Si es así, incluye el valor de la columna de referencia en la linea anterior
maxRowIndex = Cells(Rows.Count, referenceColumnIndex).End(xlUp).Row
For r = rowStartIndex To maxRowIndex Step 1
  ' Se aprovecha este bucle para sumar la cantidad total del BOM
  If Cells(r, quantityColumnIndex) <> "" Then
    initialQuantitySum = initialQuantitySum + Cells(r, quantityColumnIndex)
  End If
  
  If Cells(r, referenceColumnIndex) = "" Then
    ' Si la celda de referencia está vacía no hace nada
  ElseIf Cells(r, quantityColumnIndex) = "" Then
    Cells(r - 1, referenceColumnIndex).Value = Cells(r - 1, referenceColumnIndex).Value + Cells(r, referenceColumnIndex).Value
    Cells(r, referenceColumnIndex).EntireRow.Delete
    r = r - 1
  End If
Next r


' Orden de la celda de referencia inicial
Columns(referenceColumnIndex + 1).Insert
Columns(referenceColumnIndex + 1).Insert


maxColumnIndex = Cells(1, Columns.Count).End(xlToLeft).Column
maxRowIndex = Cells(Rows.Count, referenceColumnIndex).End(xlUp).Row


For r = rowStartIndex To maxRowIndex Step 1
  xLen = VBA.Len(Cells(r, referenceColumnIndex).Value)
  
  ' Por cada uno de los caracteres de la celda de referencia se separan las letras y números en las celdas temporales insertadas
  For i = 1 To xLen
    xStr = VBA.Mid(Cells(r, referenceColumnIndex).Value, i, 1)
    
    ' Si el valor es una coma se pone en ambas celdas para seguir con la separación
    ' Si es un número, se añade a a 2º celda insertada, si no a la 1º.
    If xStr = "," Then
      Cells(r, referenceColumnIndex + 1).Value = Cells(r, referenceColumnIndex + 1).Value + "_"
      Cells(r, referenceColumnIndex + 2).Value = CStr(Cells(r, referenceColumnIndex + 2).Value) + "_"
    ElseIf VBA.IsNumeric(xStr) Then
      Cells(r, referenceColumnIndex + 2).Value = CStr(Cells(r, referenceColumnIndex + 2).Value) + CStr(xStr)
    Else
      Cells(r, referenceColumnIndex + 1).Value = Cells(r, referenceColumnIndex + 1).Value + xStr
    End If
  Next i
  
  ' Si la celda de números tiene algún valor y además hay alguna coma (es decir, hay más de uno), ordena los valores de dentro de la celda numéricamente
  If Cells(r, referenceColumnIndex + 2) <> "" And InStr(Cells(r, referenceColumnIndex + 2), "_") <> 0 Then
    SortVals r, referenceColumnIndex + 2, "_"
    Cells(r, referenceColumnIndex + 1) = Split(Cells(r, referenceColumnIndex + 1), "_")(0)
    Cells(r, referenceColumnIndex + 2) = Split(Cells(r, referenceColumnIndex + 2), "_")(0)
  End If
Next r


' Una vez separados caracteres y números en diferentes celdas, se ordena la tabla por ambas columnas y después se eliminan
Cells.Sort _
    Key1:=Columns(referenceColumnIndex + 1), order1:=xlAscending, DataOption1:=xlSortNormal, _
    key2:=Columns(referenceColumnIndex + 2), order2:=xlAscending, DataOption2:=xlSortNormal, _
    Header:=xlYes
    
Columns(referenceColumnIndex + 1).Delete
Columns(referenceColumnIndex + 1).Delete




' Separación de valores de la columna de referencia:
'   Recorre el listado desde abajo, añadiendo tantas filas como referencias existan (separadas por coma).
'   La columna de cantidad debería resultar 1, si no es así significa que el valor inicial no concuerda con el
'   número de referencias separadas por comas.
'   Copia los valores del resto de columnas en las filas añadidas.
maxColumnIndex = Cells(1, Columns.Count).End(xlToLeft).Column
maxRowIndex = Cells(Rows.Count, referenceColumnIndex).End(xlUp).Row
For r = maxRowIndex To rowStartIndex Step -1
  If Cells(r, referenceColumnIndex) = "" Or InStr(Cells(r, referenceColumnIndex), ",") = 0 Then
    ' Si la celda de referencia está vacía o no tiene ninguna coma no hay que hacer nada con esta fila
  ElseIf InStr(Cells(r, referenceColumnIndex), ",") > 0 Then
    referenceSplit = Split(Trim(Cells(r, referenceColumnIndex)), ",")
    Rows(r + 1).Resize(UBound(referenceSplit)).Insert
    
    For c = 1 To maxColumnIndex Step 1
      If c = quantityColumnIndex Or c = referenceColumnIndex Then
        ' Si la columna es la de cantidad o referencia, no hace nada
      Else
        Cells(r, c).Resize(UBound(referenceSplit) + 1).Value = Cells(r, c).Value
      End If
    Next c
    
    '
    Cells(r, quantityColumnIndex).Resize(UBound(referenceSplit) + 1) = Cells(r, quantityColumnIndex) / (UBound(referenceSplit) + 1)
    Cells(r, referenceColumnIndex).Resize(UBound(referenceSplit) + 1) = Application.Transpose(referenceSplit)
  End If
Next r


' Eliminación de espacios en la celda de referencia
maxRowIndex = Cells(Rows.Count, referenceColumnIndex).End(xlUp).Row
For r = rowStartIndex To maxRowIndex Step 1
  Cells(r, referenceColumnIndex).Value = Replace(Cells(r, referenceColumnIndex).Value, " ", "")
Next r


' Comprobación de errores:
'   Se comprueba que en todas las celdas de cantidad el resultado haya sido 1, si no es así significa que
'   la cantidad inicial no era igual al número de referencias separadas por comas.
'   También se comprueba que la suma de todas las cantidades sea igual a la suma inicial.
For r = rowStartIndex To maxRowIndex Step 1
  If Cells(r, quantityColumnIndex) <> "" And Cells(r, quantityColumnIndex) <> 1 Then
    hasError = True
    Exit For
  End If
  
  resultQuantitySum = resultQuantitySum + Cells(r, quantityColumnIndex)
Next r


If hasError Then
  MsgBox "Error en la linea " & r & ", la cantidad inicial no correspondía con el número de referencias existentes"
  Rows(r).Select
  ActiveWindow.ScrollRow = Selection.Row
ElseIf initialQuantitySum <> resultQuantitySum Then
  MsgBox "La suma de las cantidades (" & initialQuantitySum & ") es distinta a la suma inicial (" & resultQuantitySum & ")"
End If


' Orden por referencia final
Columns(referenceColumnIndex + 1).Insert
Columns(referenceColumnIndex + 1).Insert


Dim previousItem As String
Dim currentItemIndex As Long: currentItemIndex = 0


' Similar al orden inicial, solo que esta vez, al haber ya pre-ordenado los items según su referencia más alta,
' sólo hay que reordenar dentro de cada item
For r = rowStartIndex To maxRowIndex Step 1
  xLen = VBA.Len(Cells(r, referenceColumnIndex).Value)
  
  ' Si cambia el valor de la columna de item, se suma +1 al índice del item actual
  If Cells(r, itemColumnIndex).Value <> previousItem Then
    previousItem = Cells(r, itemColumnIndex).Value
    currentItemIndex = currentItemIndex + 1
  End If
  
  For i = 1 To xLen
    xStr = VBA.Mid(Cells(r, referenceColumnIndex).Value, i, 1)
    
    If VBA.IsNumeric(xStr) Then
      Cells(r, referenceColumnIndex + 2).Value = CStr(Cells(r, referenceColumnIndex + 2).Value) + CStr(xStr)
    Else
      Cells(r, referenceColumnIndex + 1).Value = Cells(r, referenceColumnIndex + 1).Value + xStr
    End If
  Next i
  
  ' A la columna temporal con la letra se le añade el índice del item para que, a la hora de reordenar, no mezcle los items con mismo carácter de referencia
  If Cells(r, referenceColumnIndex + 1).Value <> "" Then
    Cells(r, referenceColumnIndex + 1).Value = Cells(r, referenceColumnIndex + 1).Value + Format(currentItemIndex, "000000")
  End If
Next r


Cells.Sort _
    Key1:=Columns(referenceColumnIndex + 1), order1:=xlAscending, DataOption1:=xlSortNormal, _
    key2:=Columns(referenceColumnIndex + 2), order2:=xlAscending, DataOption2:=xlSortNormal, _
    Header:=xlYes
    
Columns(referenceColumnIndex + 1).Delete
Columns(referenceColumnIndex + 1).Delete


Application.ScreenUpdating = True


End Sub


Public Sub SortVals(rowIndex As Long, columnIndex As Long, separator As String)
    Dim i As Integer
    Dim arr As Variant
    arr = Split(Cells(rowIndex, columnIndex).Text, separator)


    ' trim values so sort will work properly
    For i = LBound(arr) To UBound(arr)
        arr(i) = Format(Trim(arr(i)), "0000000")
    Next i


    ' sort
    QuickSort arr, LBound(arr), UBound(arr)


    ' load sorted values back to cell
    Dim nextSeparator As String: nextSeparator = ""
    Cells(rowIndex, columnIndex) = ""
    For i = LBound(arr) To UBound(arr)
        Cells(rowIndex, columnIndex) = Cells(rowIndex, columnIndex) & nextSeparator & CStr(arr(i))
        nextSeparator = separator
    Next i
End Sub


Public Sub QuickSort(vArray As Variant, inLow As Long, inHi As Long)


  Dim pivot   As Variant
  Dim tmpSwap As Variant
  Dim tmpLow  As Long
  Dim tmpHi   As Long


  tmpLow = inLow
  tmpHi = inHi


  pivot = vArray((inLow + inHi) \ 2)


  While (tmpLow <= tmpHi)


     While (vArray(tmpLow) < pivot And tmpLow < inHi)
        tmpLow = tmpLow + 1
     Wend


     While (pivot < vArray(tmpHi) And tmpHi > inLow)
        tmpHi = tmpHi - 1
     Wend


     If (tmpLow <= tmpHi) Then
        tmpSwap = vArray(tmpLow)
        vArray(tmpLow) = vArray(tmpHi)
        vArray(tmpHi) = tmpSwap
        tmpLow = tmpLow + 1
        tmpHi = tmpHi - 1
     End If


  Wend


  If (inLow < tmpHi) Then QuickSort vArray, inLow, tmpHi
  If (tmpLow < inHi) Then QuickSort vArray, tmpLow, inHi


End Sub
 
Upvote 0
Re: split BOM by reference designators
Just registered because I wanted to say thank you very much, hiker95, this saved me a lot of work.

By the way, I talked with a colleague at work and wanted to add an improvement, so he did the coding. This improvement is for me, I hope it can be useful for others too.

Not only splits the designators, but also sorts them but the right way (C1, C2, C3, ... instead of C1,C10,C100,C2,C20, ...).
It also run some checks like if the quantities before and after splitting are the same.

iblanco,

Welcome to the MrExcel forum.

Thanks for the feedback.

You are very welcome. Glad I could help.

I am also glad that your colleague at work was able to code an improvement.

And, come back anytime.
 
Upvote 0
Hi,
this macro in page 1 work very well.
Is it possible to change this macro to permit to copy also the right cells, for example value in cells E, F, G ?
this because i like to cop for example also descriptions, Part number,...ecc..
Thanks a lot
 
Upvote 0
ffgg123,

Welcome to the MrExcel forum.

It is always easier to help and test possible solutions if we could work with your actual file.

Perhaps you could upload a copy of your file to a free site such as www.box.com or www.dropbox.com.

Once you do that, mark it for 'Sharing' and you will be given a link to the file that you can post here.

Include a detailed explanation of what you would like to do referring to specific cells and worksheets.

If the workbook contains confidential information, you could replace it with generic data.
 
Upvote 0
Hi,
can be ok if the file is share here: https://we.tl/t-7ArLsYeu63 ?

What I like, is to have the same file with differente order as for example:
from this format
quantity
Designator
value
tollerance
voltage
temperature
description
case
manufacturer
P/N
4
R1,R2,R5,R10
100nF
5%
16V
x7r
capacitor
0402
murata
pn1
2
R3,R4
1nF
10%
16V
x7r
capacitor
0402
murata
pn2
1
R19
1uF
5%
16V
x7r
capacitor
0402
murata
pn3
1
r56
1k

<tbody>
</tbody>

to this format
quantity
Designator
value
tollerance
voltage
temperature
description
case
manufacturer
P/N
1
R1
100nF
5%
16V
x7r
capacitor
0402
murata
pn1
1
R2
100nF
5%
16V
x7r
capacitor
0402
murata
pn1
1
R5
100nF
5%
16V
x7r
capacitor
0402
murata
pn1
1
R10
100nF
5%
16V
x7r
capacitor
0402
murata
pn1
1
R3
1nF
10%
16V
x7r
capacitor
0402
murata
pn2
1
R4
1nF
10%
16V
x7r
capacitor
0402
murata
pn2
1
R19
1uF
5%
16V
x7r
capacitor
0402
murata
pn3
1
R56
1k

<tbody>
</tbody>
 
Upvote 0
ffgg123,

I am not familiar with https://we.tl/t-7ArLsYeu63, and, will not attempt to open the workbook.


It is always easier to help and test possible solutions if we could work with your actual file.

Perhaps you could upload a copy of your file to a free site such as www.box.com or www.dropbox.com.

Once you do that, mark it for 'Sharing' and you will be given a link to the file that you can post here.

Include a detailed explanation of what you would like to do referring to specific cells and worksheets.

If the workbook contains confidential information, you could replace it with generic data.
 
Upvote 0

Forum statistics

Threads
1,215,373
Messages
6,124,562
Members
449,171
Latest member
jominadeo

We've detected that you are using an adblocker.

We have a great community of people providing Excel help here, but the hosting costs are enormous. You can help keep this site running by allowing ads on MrExcel.com.
Allow Ads at MrExcel

Which adblocker are you using?

Disable AdBlock

Follow these easy steps to disable AdBlock

1)Click on the icon in the browser’s toolbar.
2)Click on the icon in the browser’s toolbar.
2)Click on the "Pause on this site" option.
Go back

Disable AdBlock Plus

Follow these easy steps to disable AdBlock Plus

1)Click on the icon in the browser’s toolbar.
2)Click on the toggle to disable it for "mrexcel.com".
Go back

Disable uBlock Origin

Follow these easy steps to disable uBlock Origin

1)Click on the icon in the browser’s toolbar.
2)Click on the "Power" button.
3)Click on the "Refresh" button.
Go back

Disable uBlock

Follow these easy steps to disable uBlock

1)Click on the icon in the browser’s toolbar.
2)Click on the "Power" button.
3)Click on the "Refresh" button.
Go back
Back
Top