Reputation: 3
I am new here.
I am trying to build a quick VBA program to "flatten" a Bill of Materials by heirarchy (BOM Level) and Status.
The sample data shows a BOM with a Car as a top level assembly, Wheel and Engine as second level assemblies, and various children parts that make up those assemblies on the third and fourth level of the BOM.
I want to delete any rows that have the value "ZE
", "ZM
", or blank in column C
.
I also want to delete any rows that have the value "ZA" and are also direct children of another "ZA
" item. (Example - Delete the Rim row from the BOM because the Wheel is the Parent "ZA
" item)
Here is what I have so far:
Sub deletechildren()
Dim lr As Long, i As Long, k As Long
lr = Cells(Rows.Count, 1).End(xlUp).Row
For i = lr To 1 Step -1
If i > 2 Then
k = i - 1
End If
If Cells(i, 3).Value = "ZA" And Cells(i, 1).Value = Cells(k, 1).Value Then
Cells(i, 3).EntireRow.Delete
ElseIf Cells(i, 3).Value = "ZE" Then
Cells(i, 3).EntireRow.Delete
ElseIf Cells(i, 3).Value = "ZM" Then
Cells(i, 3).EntireRow.Delete
ElseIf Cells(i, 3).Value = "" Then
Cells(i, 3).EntireRow.Delete
End If
Next i
lr = Cells(Rows.Count, 1).End(xlUp).Row
End Sub
I am getting some error on the first part of the If statement, where I want to parse out any "ZA
" status children from the "ZA
" parent.
Any ideas?
Upvotes: 0
Views: 3995
Reputation: 844
Sub DeleteChildren()
Dim lastRow As Long
Dim i As Long
lastRow = Cells(Rows.Count, 1).End(xlUp).Row
For i = 2 To lastRow
If (Cells(i, 3).Value = "ZE" Or Cells(i, 3).Value = "ZM" Or Cells(i, 3).Value = "") And Cells(i, 1) <> "" Then
Rows(i).EntireRow.Delete xlShiftUp
i = i - 1
GoTo NextIteration
End If
If Cells(i, 1).Value > 1 Then
If (Cells(i, 3).Value = "ZA" And Cells(i - 1, 3).Value = "ZA") And Not Cells(i, 1).Value < Cells(i - 1, 1).Value Then ' This way is a there are multiple levels with "ZA" there can
Cells(i, 5).Value = "Delete"
End If
End If
NextIteration:
Next i
lastRow = Cells(Rows.Count, 1).End(xlUp).Row
For i = 1 To lastRow
If Cells(i, 5).Value = "Delete" Then
Rows(i).EntireRow.Delete xlShiftUp
i = i - 1
End If
Next i
End Sub
Upvotes: 1
Reputation: 29421
I'd use Autofilter()
and Sort()
methods of Range
object like follows:
Option Explicit
Sub deletechildren()
Dim i As Long
With Worksheets("BOM")
With .Range("A1:D" & .Cells(.Rows.Count, 1).End(xlUp).Row)
.AutoFilter Field:=3, Criteria1:=Array("ZE", "ZM", "="), Operator:=xlFilterValues
With .Offset(1).Resize(.Rows.Count - 1)
If Application.WorksheetFunction.Subtotal(103, .Columns(1)) > 1 Then .SpecialCells(xlCellTypeVisible).EntireRow.Delete
End With
.AutoFilter
.Sort key1:=Range("C1"), order1:=xlAscending, key2:=Range("A1"), order2:=xlAscending, Header:=xlYes
i = .Rows(.Rows.Count).Row
Do Until .Cells(i, 1) = .Cells(2, 1)
i = i - 1
Loop
If i < .Rows.Count Then .Rows(i + 1).Resize(.Rows.Count - i).EntireRow.Delete
End With
End With
End Sub
Upvotes: 0
Reputation: 5770
A part of the problem is that the variable k
is not being used to correctly identify parent/children relationships (if I understand your requirements correctly). In your case, you are comparing the each value with the row above it, but in a bill of materials, the parent row might be multiple rows above, and is denoted by a hierarchy value - 1.
See my revised code below. In the code, we first delete any rows that we know to delete (ZM, ZE, and Blanks). Next, we loop up the hierarchy values until we find one hierarchy value above the current row. That becomes the parent row, and from there, we test.
Let me know if you need additional help.
Sub deletechildren()
Dim lr As Long, i As Long, k As Long
lr = Cells(Rows.Count, 1).End(xlUp).Row
For i = lr To 1 Step -1
If i > 2 Then
k = i - 1
If Cells(i, 3) = "ZE" Or Cells(i, 3) = "ZM" Or Cells(i, 3) = "" Then
Rows(i).Delete
Else
k = i - 1
Do Until i <= 2 Or (Cells(i, 1) - Cells(k, 1) = 1)
k = k - 1
Loop
'Now, k represents the parent row.
If Cells(i, 3) = "ZA" And Cells(k, 3) = "ZA" Then
Rows(i).Delete
End If
End If
End If
Next i
lr = Cells(Rows.Count, 1).End(xlUp).Row
End Sub
Upvotes: 0