VBA nonsense pointing at the wrong sheet? - excel

Some strange things are happening to me in VBA. Somedays I am coding and everything works fine, then I go out of the code and the next day when I want to run the exact same code from the day before the code doesn't go into the loop, but jumps directly into end sub().
I tried to use the Activate sheet function, it seemed to work for 10 seconds and then afterwards suddenly it didn't work again which means my code didn't go into the loop again. The reason why I was using Activate sheet function was because I was afraid that my code was pointing at the wrong excel file / sheet. I have a lot of excel files and all of the sheets in those excel files are called Sheet1 could that create problems??
To give you a concrecte example, say I day one use the following code to loop through a column:
Sub stuff()
' Sheet1.Activate
lngLastRow = Worksheets("Sheet1").Range("A" & Rows.Count).End(xlUp).Row
Set sheet1ArkRng = Worksheets("Sheet1").Range("A1:Z" & lngLastRow)
Set offsheetarkrng = Worksheets("Sheet1").Range("L5")
Dim i As Integer
For i = 3 To sheet1ArkRng.Rows.Count
sheet1VirkNavn = sheet1ArkRng.Cells(RowIndex:=i, ColumnIndex:="C").Value
Next i
End Sub
Then day 1 everything works fine and the variable sheet1VirkNavn shows me the value of the rows in column C. It can be seen when I debug.
Then day 2 once I debug the exact same code from the exact same file it goes to
"For i = 3 To sheet1ArkRng.Rows.Count"
and then jumps directly into
End sub

Problem solved:
I've learned what
lngLastRow = Worksheets("Sheet1").Range("A" & Rows.Count).End(xlUp).Row
means. Now it all makes sense. If you're using the above code to loop through last row you should use the same letter for the column you want to loop through...
So the case was my code wasn't getting into the loop simply because my "A" column was empty.

Related

How to remove duplicate row but save the latest one (VBA)?

I have an excel where I have 2 sheets and I want to import selected columns to another sheet and delete possible duplicate rows. The problem is, that when I run my code, it deletes my latest duplicate row, eventhough I want to save latest row and delete the other 'older' duplicate. I really appreciate any help! Thank you :) Here is my code what I have tried so far:
Private Sub CommandButton1_Click()
Cells.RemoveDuplicates Columns:=Array(1, 2, 3)
Dim lastrow As Long, erow As Long
lastrow = Worksheets("one").Cells(Rows.Count, 1).End(xlUp).Row
For i = 2 To lastrow
Worksheets("one").Cells(i, 1).Copy
erow = Worksheets("two").Cells(Rows.Count, 1).End(xlUp).Row
Worksheets("one").Paste Destination:=Worksheets("two").Cells(erow + 1, 1)
Worksheets("one").Cells(i, 3).Copy
Worksheets("one").Paste Destination:=Worksheets("two").Cells(erow + 1, 2)
Next i
End Sub
Another question is, I have tried this code for test excel, but where I want to use this macro has a lot larger data. It takes a very long time to go through all the data.. is the problem in my code or is the actual excel just so big? I hope I explain everything crearly.
Thank you!
"The problem is, that when I run my code, it deletes my latest duplicate row..."
The problem is the sort order of your data.
Remove Duplicates moves from first index to last and and keeps the first occurrence. So you either need to sort your data such that your "oldest" duplicate is the first occurrence at top or you have to use a different method to remove duplicates.
"is the problem in my code or is the actual excel just so big?"
It could be both, but one thing is certain, your code can definitely run faster.
The low hanging fruit is to put Application.EnableScreenUpdating = False in the beginning of you sub. That stops Excel from updating the screen when your runs. It will make a huge difference. Just remember to set it back to True again.
You're also looping through a range one row at a time but I don't see any particular reason why you need to. You can copy the while range in a single statement without looping. You don't even need to copy of you don't care about ordering the format, you could transfer the values just make the ranges equal each other.
An example of how you to transfer values without cutting or looping
Worksheets("two").Range("A2:A" & lastrow).Value = Worksheets("one").Range("E2:E" & lastrow).Value
You can use the same approach with copy and paste if you prefer.

Need missing values from two sheets, my copy functions all work fine

I wrote some code in VBA to bring back values missing from two sheets. When I entered just the index match function into the code, the code ran great. But I wanted to bring back only values that were missing instead of all values and N/A's so I wrote a function adding in an extra if statement and an ISNA. When I run the function in excel it works, but when I add it to my code it fails.
I have tried reformatting it but it seems to be in the code appropriately.
Sub IndexMatch_Formula()
' Index Match Formula
Dim Wa As Worksheet
Dim LastRow As Long
LastRow = Worksheets("Analysis").Cells(Rows.Count, "A").End(xlUp).Row
Set Wa = ThisWorkbook.Sheets("Analysis")
With Wa
'C
.Range("C2").Formula = "=IF(ISNA(IF(INDEX(B:B,MATCH(A2,B:B,0))=INDEX(B:B,MATCH(A2,B:B,0)),"",A2))=TRUE,A2,"")"
.Range("C2").AutoFill Destination:=Worksheets("Analysis").Range("C2:C" & LastRow)
End With
End Sub
I expect the code to bring back only missing values from two sheets.
You need to add 2x" around your double-quote:
.Range("C2").Formula = "=IF(ISNA(IF(INDEX(B:B,MATCH(A2,B:B,0))=INDEX(B:B,MATCH(A2,B:B,0)),"""",A2))=TRUE,A2,"""")"

Searching data from one spreadsheet into another

I'm making a macro that is supposed to check for a set of values in an input list from the user. If the values from my source list are NOT in the user input, they have to be copied into a different spreadsheet. The macro runs without errors, but it won't filter any results. It just copies everything.
This is the code:
Sub CheckRow()
For i = 2 To Application.CountA(Worksheets("Source").Range("A:A")) 'Loop through rows
Set rgFound = Worksheets("Input").Range("A:A").Find(Worksheets("Source").Range("A" & i).Value, LookAt:=xlWhole) 'Find the value from the source list in the Input List
If rgFound Is Nothing Then 'If there is no match it goes to output
Worksheets("Output").Range("A" & Application.CountA(Worksheets("Output").Range("A:A")) + 1).Value = Worksheets("Source").Range("A" & i).Value 'Copy the value beow any existing values
End If
Next i
End Sub
I will appreciate any suggestions you have to offer.
Your condition should be If Not rgFound Is Nothing Then (the Not is missing in your code). Basically, the Find method doesn't find anything and therefore everything is copied.
I also advise you to use Option Explicit at the top of your code sheet. This would alert you to the use of the variable j in Find(Worksheets("Source").Range("A" & j). I think you are looking for A & i. However, since j appears to have a value of 0 your code shouldn't copy anything because there is no row 0. Using Option Explicit would force you to declare all variables, eliminating guessing games like this one when reading your code. Since you are the one to read it most of the time you would also be the prime beneficiary of the improvement.
Fixed. It seems that the Find method thinks that Value and ="Value" are two different things. Once I changed all the formula cells to plain text my code worked like a charm.

How can I use a command button to update a range of cells based on their current values in Excel?

I am working in Excel and trying to create a command button that will update the value in a cell based on the current value of the cell, down the entire column.
More specifically, I have a column with location IDs which are integers. At a click, I want all cells within that column that contain the values 1 or 2 to be changed to 10. Then, I want to run a prerecorded sort macro.
I have found information on cascading If statements, which seems to be the key. I thought something like the following might work, but it keeps telling me I have a logic error.
Private Sub CommandButton1_Click()
If Range("LocationID") = 1 Then
Range("LocationID") = 10
Else
If Range("LocationID") = 2 Then
Range("LocationID") = 10
End If
End Sub
Location is the column I am trying to search and change.I have not added my sort macro into this yet, because I assume that works like any other button that calls a macro.
This is probably really basic, but VBA is totally foreign to me. I've been banging my head against this problem all morning. Thanks for the help!
It sounds like you mean something like this:
Private Sub CommandButton1_Click()
Dim lRow As Long
lRow = 1
Do Until Range("A" & lRow) = ""
Select Case Range("A" & lRow)
Case 1, 2
Range("A" & lRow) = 10
End Select
lRow = lRow + 1
Loop
End Sub
Note: I just guessed that it's column A. You will want to change that in all 3 places to the column that has the value you want.

Excel VBA - Loop to filter table for each value in column and paste in according worksheet

I am trying to filter a table on the first worksheet ("Data") for each of the items that appear in a table on the second worksheet ("Hosts"), and then paste the filtered results in separate worksheets, each named after the corresponding item on the table.
My understanding of VBA is very basic and I have tried to put together a collage of codes from other users, but it doesn't seem to work properly for me:
The first loop creates worksheets based on the items on the "Hosts" table, but for some reason it adds an extra sheet before the ones I need and calls it "Sheet1"
The second loop simply doesn't work
Are two loops really necessary, or is it possible to combine the two?
This is the code I have so far:
Sub test()
Dim AllData As Worksheet
Dim HostList As Worksheet
Dim DataRange As Range
Dim FilterColumn As Long
Set AllData = ThisWorkbook.Worksheets("Data")
Set HostList = ThisWorkbook.Worksheets("Hosts")
Set DataRange = AllData.Range(Range("A1"), Range("A1").SpecialCells(xlLastCell))
Dim HostValues As Range
For Each HostValues In HostList.ListObjects("Table1").Range
With ThisWorkbook.Sheets.Add(After:=ThisWorkbook.Sheets(ThisWorkbook.Sheets.Count))
On Error Resume Next
ActiveSheet.Name = HostValues.Value
If Err.Number = 1004 Then
Debug.Print HostValues.Value & "already used as a sheet name"
End If
On Error GoTo 0
End With
Next HostValues
For Each HostValues In HostList.ListObjects("Table1").Range
AllData.Activate
FilterColumn = 18
DataRange.AutoFilter Field:=FilterColumn, Criteria1:=HostValues
DataRange.SpecialCells(xlCellTypeVisible).Copy
Sheets(HostValues.Text).Range("A1").PasteSpecial xlPasteValues
Selection.Sort Key1:=Range("V:V"), Order1:=xlAscending, Header:=xlGuess
AllData.Activate
Cells.AutoFilter
Next HostValues
End Sub
Some kind soul out there please help me!
There's quite a bit to do here, but I'll give it a shot.
The first loop creates worksheets based on the items on the "Hosts" table, but for some reason it adds an extra sheet before the ones I need and calls it "Sheet1"
My guess here is that Hosts contains a duplicate entry or something is causing the sheet rename section to fail. I would check the debug window for that. Or change
Debug.Print HostValues.Value & "already used as a sheet name"
to
msgBox HostValues.Value & "already used as a sheet name"
That will make a popup happen, should make it easier to see when the error happens. Something else you can try, comment out the two OnError statements with a ' single quote. Then when an error is raised you can hit debug and work through what the program is upset with.
The second loop simply doesn't work
I'm not sure on this one. When you use a For Each many times changing the collection it is operating on will give you some sort of problem. You've asked the computer to do something for every cell in this column, and then you change the values of the column. That's just a guess.
Are two loops really necessary, or is it possible to combine the two?
You can combine the two, after creating the sheet for the Host you can move its data over to it.
Notes
The approach with filtering may be giving you undue complexity try writing a loop without the filters and checking if the Host has a sheet, if it does move the data. If it does not create it and move the data.
You do not need the With/End With block at all.
On Error Resume Next is dangerous. It has its uses, take a look at this for more information or handling errors.
Godspeed.

Resources