I have written this VBA code that goes through a set of data and aligns specific rows of data together and deletes the rest. I have various columns labeled as below. Whenever "Billed" appears under the "M" column, my program records the order number associated with that row under "B". It then loops and while the order number under "B" is consistent, it moves the notes under "L" associated with "Completed" and copies it besides the column and the same under where "Billed" was found. In addition, when it also moves the date under column "D" for "Confirmed" associated with that same order number and again adds to the column beside the "Billed" row. The problem I am running into is that none of these rows appear in the same order and also there can be duplicates. If there's a duplicate like the one in second order number for "Confirmed" then the most recent one will be taken and copied over beside "Billed". Any help would be tremendously appreciated! Thanks a lot in advance. Here is an Example:-
B D L M
1.467334 4/22/2015 Confirmed
2.467334 4/17/2015 YES Tech swapped out the MGR 13, tested Completed
3.467334 4/20/2015 4/16 Maint. Billed Billed
4.537551 4/15/2015 Confirmed
5.537551 4/14/2015 YES Tech swapped out the MGR 13, tested Confirmed
6.537551 4/08/2015 4/16 Maint. Billed Billed
7.537551 4/14/2015 YES Tech swapped out equipment Completed
8.537551 4/08/2015 4/16 Maint. equip. Confirmed
Required Output:-
B D L M Q R
3.467334 4/20/2015 4/16 Maint. Billed Billed YES swapped out theMGR 13, tested 4/22/2015
6.537551 4/16/2015 4/16 Maint. Billed Billed YES Tech swapped out equipment 4/14/2015
Here is my code:
Sub Test()
Dim LR As Long
Dim Rng As Range
Dim i As Long
Dim r As Long
Dim com As Range
LR = Range("A" & Rows.Count).End(xlUp).Row
For i = 2 To LR Step 1
''''This might be confusing but what I am doing here is copying the notes for the "Billed" row and moving to the right.
'This part works fine but the rest of the "Do While" loop doesn't.
If Cells(i, "M").Value = "Billed" Then
Cells(i, "Q").Value = Cells(i, 12).Value
Set com = Cells(i, "B")
Set num = Cells(i, "B").Row
Do While Cells(i, "B").Value = com
If Cells(i, "M") = "Completed" Then
Cells(num, "R").Value = Cells(i, 12).Value
End If
Loop
Do While Cells(i, "B").Value = com
If Cells(i, "M") = "Confirmed" Then
Cells(num, "S").Value = Cells(i, 4).Value
End If
Loop
End If
Next i
Your issue is here:
Do While Cells(i, "B").Value = com
If Cells(i, "M") = "Completed" Then
Cells(num, "R").Value = Cells(i, 12).Value
End If
Loop
Do While Cells(i, "B").Value = com will always be true, because neither i nor com are changing inside your loop. In some way shape or form, you need to adjust the value of one of those two variables within that loop. I believe that a simple i = i + 1 will do what you're after, like this:
Do While Cells(i, "B").Value = com
If Cells(i, "M") = "Completed" Then
Cells(num, "R").Value = Cells(i, 12).Value
End If
i = i + 1
Loop
Just realized that won't work, since i is the counter in your For...Next loop. Instead, try this:
r = i
Do While Cells(r, "B").Value = com
If Cells(r, "M") = "Completed" Then
Cells(num, "R").Value = Cells(r, 12).Value
End If
r = r + 1
Loop
You've declared r, but never used it, so I usurped it for this loop.
The same holds true for your next Do While...Loop block.
A couple of additional thoughts:
You're mixing reference between Cells(i, "M") and Cells(i, 12). While the compiler doesn't care and can easily interpret that, it's harder for us people types to figure out what column is being referenced - is M the 12th letter? No, it's the 13th, so that mean... oh, Column L!
Use consistent block indention - that also makes your code much easier to read and mentally parse. Again, the compiler doesn't care, but you, or the person maintaining the code after you, will appreciate it.
You mention that there's an issue with duplicate order numbers. I'm not seeing that unless the 1., 2., etc are indicating line numbers instead of decimal values. If this is the case, I'd suggest having your code sort the data in an order that makes sense for your purposes, then have your code written in that sorted order. That way, you can expressly handle the duplicate values - for example if OrderNum(row) = OrderNum(row-1) then and check the dates to pick up the newest one.
Related
I'm struggling with the following: I want to delete rows for which date (column C) is prior than today. My code should work (according to the web) but it doesn't and moreover, it's super slow.. Here is a part of it:
For i = 2 To LastRow
If Cells(i, "C").Value < Date Then Rows(i).EntireRow.Delete
Next i
Instead of putting "C", I could put 3, but doesn't change anything. I've tried to add the End If (before the next i), but not necessary apparently. Maybe the Date is not the right format..
What's wrong with this code ?
Great thanks for your help :)
Use the auto-filter capabilities of Excel in your favor. Filter the range by your criteria to delete the matching rows:
With Range("C1:C" & lastrow)
.AutoFilter 1, "<" & CLng(Date)
.Offset(1).EntireRow.Delete
.AutoFilter
End With
You will want to step backwards when deleting rows and verify that it is actually a date in the cell. To see what it's doing, set a breakpoint on the first line and use F8 to step through it. Also verify the value of LastRow is getting set to the correct value.
For i = LastRow To 2 Step -1
If IsDate(Cells(i, "C").Value) then
If Cells(i, "C").Value < Date Then Rows(i).EntireRow.Delete
End If
Next i
Recently started working with VBA. Youtube and this forum have been excellent help so far. However, my problem is this:
Private Sub CommandButton1_Click()
Dim i As Integer
i = 1
Do While Sheet2.Cells(i, 1).Value <> 0
Sheet3.Cells(i, 1).Value = Sheet2.Cells(i, 1)
i = i + 1
Loop
Do While Sheet2.Cells(i, 10).Value <> 0
Sheet3.Cells(i, 4).Value = Sheet2.Cells(i, 10)
i = i - 1
Loop
Do While Sheet2.Cells(i, 6).Value <> 2
Sheet3.Cells(i, 3).Value = Sheet2.Cells(i, 6)
i = i + 1
Loop
End Sub
This script populates information in the correct sheet as well as the correct columns, at least until it encounters an empty cell from Sheet2. At this point is moves on to the next "Do While" instead of referring to the next non blank cell.
I've also encountered a Runtime Error 6- Overflow with this specific line:
Do While Sheet2.Cells(i, 6).Value <> 2
Sheet3.Cells(i, 3).Value = Sheet2.Cells(i, 6)
i = i + 1 <<<<----- ERROR??
I'm fairly certain that the Overflow Error is a result of Dim i as Integer vs. Dim i as String, but then again I've pretty much but working by trial and error, moving portions of script around and playing with expressions/functions.
As mentioned before I'm new to VBA. I'm also the kind of guy that learns by doing as well. I've looked all over different forums, youtube videos, etc. trying to create a script that works the way I want it to.
UPDATE
Thanks for the quick help and recommendations. I realized I didn't give near enough information in my first post.
1.) I don't need/want to leave an empty cell on sheet3. The script is now looping but not skipping over blanks if that makes sense?
For example:
doing need to do
101 101
102 102
104
104 105
105 106
106
I'm stil running off the end of the world as well so to speak. For some reason the Debug Function is bringing up this line
i = i + 1
2.) the line:
Do While Sheet2.Cells(i, 6).Value <> 2
Sheet3.Cells(i, 3).Value = Sheet2.Cells(i, 6)
is supposed to recognize a column of text not numbers. Not exactly sure if this is having an effect on anything
Thanks again everyone.
UPDATE 3:
I've got rid of the Error Messages and corrected all the expressions in the script. Also, I found that instead of using Do Until....... And........ had zero results. I had to go back to Do While and substitute an Or statement vs. the former.
So far the script is working better than I had expected. Thank You all for the help and insight.
Good news aside, I still need to figure out how to compose an "IF" statement so that the script will skip over blank cells in sheet2.cells(i, 1) and not import present values for that row in the 2 adjacent columns
Here is the current and running script:
Private Sub CommandButton1_Click()
Dim i As Long
i = 3
Do While (Not IsEmpty(Sheet2.Cells(i, 10))) Or (Sheet3.Cells(i, 4).Value <> 0)
Sheet3.Cells(i, 4).Value = Sheet2.Cells(i, 10).Value
i = i + 1
Loop
i = 3
Do While (Not IsEmpty(Sheet2.Cells(i, 1))) Or (Sheet3.Cells(i, 1).Value <> 0)
Sheet3.Cells(i, 1).Value = Sheet2.Cells(i, 1).Value
i = i + 1
Loop
i = 3
Do While (Not IsEmpty(Sheet2.Cells(i, 6))) Or (Sheet3.Cells(i, 3).Value <> 0)
Sheet3.Cells(i, 3).Value = Sheet2.Cells(i, 6).Value
i = i + 1
Loop
End Sub
Thank you again everyone. Hope I can return the favor in the near future.
A few thoughts:
As #dgorti said, make sure to set i before each Do loop to be the index of the row you want to start with.
Dim any integer value as Long, not Integer. Long is 32 bits; Integer is 16.
To skip over empty cells, use IsEmpty. For example, in your first loop: Edited
Do Until (Not IsEmpty(Sheet2.Cells(i, 1))) and (Sheet2.Cells(i, 1).Value = 0)
Edit And, as #A.S.H. points out, you should also range-check i. Since VBA doesn't have short-circuit operators, I would do that at the end of your loop:
Do ...
... 'vvvvv representable in a Long
If i = 65536 Then Exit Do ' Or If i = 1... for loops that count down
i = i + 1
Loop
That way you never run off the end.
Edit I fixed the test above — you want to run until you hit a non-empty cell with a value of 0, right? So Do Until (which is a real thing :) ) loops until exactly that condition holds. The Not IsEmpty() prevents the test against 0 from giving the wrong result on blank cells.
I initially asked a question below.
Basically I want VBA to look at Column L:L. If the cell=program, and the cell below does not equal lathe I want the row above to be deleted. If the cell doesn't equal program continue looking until the end of the data.
Realized I needed to look at the data different, as I was losing rows that I needed to stay.
New logic, which I think will still use some of the old program, but
it needed to be sorted using another column. I need the VBA to look at
column E:E. If the cell in the row below is a duplicate of the cell
above, then look at column L in that row to see if the cell says
Program. If so the cell below should be Lathe. If not lathe delete the
Program Row, If it is Lathe leave both rows. If the Cells in Column E
are not duplicates, continue looking. EX. If E5=E6, If not continue
looking. If yes Look at L5 to see if it say Program. If so look at L6
for Lathe. If not delete ROW5.
This I what I received that answered teh first question which I think will still get used
Dim rngCheck as Range
Dim rngCell as Range
Set rngCheck = Range("L1", "L" & Rows.Count - 1)
For each rngCell in rngCheck
If rngCell.value = "Program" And rngCell.offset(1,0).value <> "lathe" then
rngCell.offset(-1,0).EntireRow.Delete
End if
Next rngCell
This should do it
For i = ThisWorksheet.Cells.SpecialCells(xlCellTypeLastCell).Row to 2 step -1
' that row do you mean the duplicate or the original (I am using original)
If ThisWorksheet.Cells(i, 5) = ThisWorksheet.Cells(i-1, 5) and _
ThisWorksheet.Cells(i-1, 12) = "Program" and ThisWorksheet.Cells(i, 12) <> "Lathe"
ThisWorksheet.Rows(i-1).EntireRow.Delete
End If
Next i
When deleting it is best to iterate from last to first. If prevent you from skipping rows.
Sub RemoveRows()
Dim x As Long
With Worksheets("Sheet1")
For x = .Range("E" & .Rows.Count).End(xlUp).Row To 2 Step -1
If .Cells(x, "E").Value = .Cells(x - 1, "E").Value And Cells(x - 1, "L").Value = "Program" Then
.Rows(x).Delete
End If
Next
End With
End Sub
I'm writing a code that copies data from one sheet into another and I've got that function working fine. Now, I'm trying to code it to delete any rows that contain duplicate information based off that information's ID number in column F. Part of our process is to manually enter in column E when each row has been worked.
So my end goal is for the code to delete rows where column E is blank and column F is a duplicate. My code runs, but doesn't delete anything. I'm really hoping I'm just missing something ridiculously obvious.
For i = 1 To Range("f" & Rows.Count).End(xlUp).Row
If Cells(i, 5).Value = "" Then 'if column E is blank on row i
x = Cells(i, 6).Value
If Not IsError(Application.Match(x, "F:F", 0)) Then '& if that row is a duplicate
ActiveSheet.Range(x).EntireRow.Delete 'delete new duplicate row
End If
End If
Next i
Try it with,
For i = Range("f" & Rows.Count).End(xlUp).Row to 1 Step -1
If Cells(i, 5).Value = "" Then 'if column E is blank on row i
x = Cells(i, 6).Value
If Application.Countif(Columns(6), x) > 1 Then '& if that row is a duplicate
Rows(i).EntireRow.Delete 'delete new duplicate row
End If
End If
Next i
You were trying to delete the row number x, not i. Additionally, everything was going to be matched once.
So there are a couple of errors that need to be addressed in your code. First, if you are looping over a range and deleting rows, it's best to start from the bottom and work your way up. This prevents issues where your iterator is on a row, that row gets deleted, and the loop essentially skips the next row.
Next, you are looking for a Match in column F of x, which contains a value from Column F. So, it will always return a value (itself, at the very minimum). Maybe try using a COUNTIF and seeing if it's greater than 1 may be a better option?
Next, you populated the variable x with the value in Cells(i, 6), but then you try to use it as a range when deleting. Change your code to the following and see if it works:
For i = Range("f" & Rows.Count).End(xlUp).Row To 1 Step -1
If Cells(i, 5).Value = "" Then 'if column E is blank on row i
x = Cells(i, 6).Value
If Application.Countif(Columns(6), x) > 1 Then '& if that row is a duplicate
ActiveSheet.Rows(i).Delete 'delete new duplicate row
End If
End If
Next i
Why not use the .RemoveDuplicates method? It's faster than looping around. Here's a rough outline on its use:
With Range
.RemoveDuplicates Columns:=Array(6), Header:=xlYes
End With
Here's the msdn doc for the method, and another page with a more detailed implementation. They should clear up any questions you might have.
Everyone!
I have a heavy file with different values in A and D columns.
Now I want this script to complete the following operation:
If value in column A is "Option One" and "K" in column D, then remove this entire line.
Additionally Remove entire raw if value in column A is "Option Two" and "M" in column D
The following code performs this operation for 70% and I can't find the issue.
It always leaves behind some rows and to completely remove unwanted entries, I have to run this code twice.
Will appreciate your help! Thank You!
Sub RemoveSomeLines()
Dim RemoveRow As Long
RemoveRow = Cells(Rows.Count, "A").End(xlUp).Row
For y = 1 To RemoveRow
If Cells(y, "A").Value = "Option One" And _
Cells(y, "D").Value = "K" Then
Cells(y, "A").EntireRow.Delete
ElseIf Cells(y, "A").Value = "Option Two" And _
Cells(y, "D").Value = "M" Then
Cells(y, "A").EntireRow.Delete
End If
Next y
End Sub
Try going backwards:
For y = RemoveRow To 1 Step -1
It is probably skipping rows because you are removing a row, moving the next row up, and then skipping the row that was moved up on the next loop because y increments by 1.
It looks like this:
Remove row 20.
Entire sheet shifts upward.
Row 21 is now row 20.
y increments on the next loop to become 21.
The new row 20 was actually skipped entirely.
Alternatively, I think it would work if you decremented y by 1 when you removed a row, but it's less code changes just to work backward instead of forward.