My mind is broken. I have spent days trying to figure out why this is happening:
After a user form is filled out there is a button to populate a corresponding spreadsheet. The sheet is determined by the first combo box (catSel.value). To find the last empty row I use the rngSrch portion of the code below.
On one sheet If Application.WorksheetFunction.CountA(Acell.EntireRow) = 0 comes back as false and firstBlankRow = Acell.row is not run.
I have tried deleting the sheet and creating a new one(copying one that works), changing the name and commenting out/changing the code.
Any ideas why this is happening? Also ws.Range("A" & firstBlankRow) = Me.equipId.value is coming back with Run-time Error ‘1004’: method ‘Range’ of object ’_worksheet’ failed
Private Sub AddCont_Click()
Dim firstBlankRow As Long
Dim ws As Worksheet
Dim srchRng As Range
Dim Acell As Range
Set ws = Worksheets(CatSel.value)
On Error GoTo Err
With ws
Set srchRng = .UsedRange.Columns(1).Find("")
If Not srchRng Is Nothing Then
Set srchRng =.UsedRange.Columns(1).SpecialCells(xlCellTypeBlanks)
For Each Acell In srchRng
If Application.WorksheetFunction.CountA(Acell.EntireRow) = 0 Then
firstBlankRow = Acell.row
Exit For
End If
Next
Else
If Application.WorksheetFunction.CountA(Cells(.Rows.Count, 1).EntireRow) = 0 Then
MsgBox "Please start a new sheet"
Else
firstBlankRow = .UsedRange.SpecialCells(xlCellTypeBlanks).row + 1
End If
End If
'Equipment ID
ws.Range("A" & firstBlankRow) = Me.equipId.value
'Parent or Next Level
ws.Range("B" & firstBlankRow) = Me.NextLev.value
'Keyword
ws.Range("C" & firstBlankRow) = Me.KeySel.value
'Cost Center
ws.Range("E" & firstBlankRow) = Me.CostSel.value
'Department
ws.Range("F" & firstBlankRow) = Me.DepartSel.value
'Location 1
ws.Range("G" & firstBlankRow) = Me.Loc1.value
'Location 2
ws.Range("H" & firstBlankRow) = Me.Loc2.value
'Location 3
ws.Range("I" & firstBlankRow) = Me.Loc3.value
'Location 4
ws.Range("J" & firstBlankRow) = Me.Loc4.value
'Beginning of specs
'L5
ws.Range("L" & firstBlankRow) = Me.L3Sel.value
'M5
ws.Range("M" & firstBlankRow) = Me.M3Sel.value
'N5
ws.Range("N" & firstBlankRow) = Me.N3sel.value
'O5
ws.Range("O" & firstBlankRow) = Me.O3Sel.value
'P5
ws.Range("P" & firstBlankRow) = Me.P3Sel.value
'Q5
ws.Range("Q" & firstBlankRow) = Me.Q3Sel.value
'R5
ws.Range("R" & firstBlankRow) = Me.R3Sel.value
'S5
ws.Range("S" & firstBlankRow) = Me.S3Sel.value
'T5
ws.Range("T" & firstBlankRow) = Me.T3Sel.value
'U5
ws.Range("U" & firstBlankRow) = Me.U3Sel.value
MsgBox ("successfully Added")
End With
Err: MsgBox ("something went wrong")
End Sub
I think in this part of the code
Set srchRng = .UsedRange.Columns(1).Find("")
If Not srchRng Is Nothing Then
Set srchRng =.UsedRange.Columns(1).SpecialCells(xlCellTypeBlanks)
For Each Acell In srchRng
If Application.WorksheetFunction.CountA(Acell.EntireRow) = 0 Then
firstBlankRow = Acell.row
Exit For
End If
Next
Else
If Application.WorksheetFunction.CountA(Cells(.Rows.Count, 1).EntireRow) = 0 Then
MsgBox "Please start a new sheet"
Else
firstBlankRow = .UsedRange.SpecialCells(xlCellTypeBlanks).row + 1
End If
End If
you are trying to find the first blank row, so that you can insert a new record.
If so, I suggest you replace that code with:
If IsEmpty(.Cells(.Rows.Count, 1)) Then
firstBlankRow = .Cells(.Rows.Count, 1).End(xlUp).Row + 1
Else
MsgBox "Please start a new sheet"
Exit Sub
End If
That code will look for the last non-empty cell in column A and set the firstBlankRow variable to point to the row after it.
If your records sometimes have an empty value in column A, but you have another column that can be guaranteed to always have a value, just change the above code to refer to that column instead of to column 1. E.g. (assuming column D is always populated):
If IsEmpty(.Cells(.Rows.Count, "D")) Then
firstBlankRow = .Cells(.Rows.Count, "D").End(xlUp).Row + 1
Else
MsgBox "Please start a new sheet"
Exit Sub
End If
If you have records where no column is guaranteed to be non-empty, perhaps this code will work:
firstBlankRow = .Rows.Count + 1
If IsEmpty(.Cells(.Rows.Count, "A")) Then
For firstBlankRow = .Cells(.Rows.Count, "A").End(xlUp).Row + 1 To .Rows.Count
If Application.WorksheetFunction.CountA(.Rows(firstBlankRow)) = 0 Then
Exit For
End If
Next
End If
If firstBlankRow = .Rows.Count + 1 Then
MsgBox "Please start a new sheet"
Exit Sub
End If
Related
In my code there is a searching order and it does as folloing:
It takes each value (about 2000 ranges) in ws.sheet range A and looks it up in another sheet named wp.sheet range A (about 90 ranges). If a particular value x in ws.sheet range e.g A3 is not found in wp.sheet range A the next search order in sheet ws.sheet is the value y in the next range B3 (same row as value x) to be searched in sheet wp.sheet in the entire range B, and so on.
This is what my "for" loop does and the issue with my code is that it takes very long as it compares each value in ws.sheet range A1-2000 to the values in wp.sheet range A1-90. Is there an alternative which does it more quickly or more efficiently?
Dim wb As Workbook, wq As Object
Dim ws, wi As Worksheet, datDatum
Dim w As Long, I As Long, t As Long
Dim DefaultMsgBox()
Dim r, i As Integer
For r = 2 To 2000
Check = True:
For i = 1 To 90
If ws.Range("A" & r).Value = wp.Sheets("ABC").Range("A" & i).Value Then
wp.Sheets("ABC").Rows(i).Columns("E:AB").Copy
ws.Range("G" & r).PasteSpecial
GoTo NextR
End If
Next i
For i = 1 To 90
If ws.Range("B" & r).Value = wp.Sheets("ABC").Range("B" & i).Value Then
wp.Sheets("ABC").Rows(i).Columns("E:AB").Copy
ws.Range("G" & r).PasteSpecial
GoTo NextR
End If
Next i
For i = 1 To 90
If ws.Range("C" & r).Value = wp.Sheets("ABC").Range("C" & i).Value And ws.Range("D" & r).Value = wp.Sheets("ABC").Range("D" & i).Value Then
wp.Sheets("ABC").Rows(i).Columns("E:AB").Copy
ws.Range("G" & r).PasteSpecial
GoTo NextR
End If
Next i
NextR:
If Not Check = ws.Range("A" & r).Value = wp.Sheets("ABC").Range("A" & i).Value Or Not Check = ws.Range("B" & r).Value = wp.Sheets("ABC").Range("A" & i).Value Or Not Check = ws.Range("C" & r).Value = wp.Sheets("ABC").Range("C" & i).Value And ws.Range("D" & r).Value = wp.Sheets("ABC").Range("D" & i).Value Then
MsgBox "......"
End If
Next r
End sub
I would suggest turning off ScreenUpdating and using the Find function instead:
Dim cell, foundValue, lookupRange As Range
Set wp = ThisWorkbook.Sheets("ABC")
Set ws = ThisWorkbook.Sheets("WS")
r = 2
number_r = 2000
ru = 1
number_ru = 90
Application.ScreenUpdating = False
'Loop through each cell in WS, offsetting through columns A to C
For Each cell In ws.Range("A" & r & ":A" & number_r)
For i = 0 To 2
'Define range to look up in ABC
Set lookupRange = wp.Range(wp.Cells(ru, i + 1), wp.Cells(number_ru, i + 1))
'Look for current WS cell on corresponding column in ABC
Set foundValue = lookupRange.Find(cell.Offset(0, i).Value)
'If cell is found in ABC...
If Not foundValue Is Nothing Then
Select Case i
Case 2 'If found cell is in column C
Do 'Lookup loop start
'If same values on columns D...
If foundValue.Offset(0, 1).Value = cell.Offset(0, 3).Value Then
'Copy data to WS and switch to the next cell
wp.Rows(foundValue.Row).Columns("E:AB").Copy
ws.Range("G" & cell.Row).PasteSpecial
GoTo nextCell
'If not same values on columns D...
Else
'Try to find next match, if any
Set foundValue = lookupRange.FindNext(foundValue)
If foundValue Is Nothing Then GoTo noMatchFound
End If
Loop 'Repeat until WS values in column C and D match ABC values in columns C and D
Case Else 'If found cell is in column A or B
'Copy data to WS and switch to the next cell
wp.Rows(foundValue.Row).Columns("E:AB").Copy
ws.Range("G" & cell.Row).PasteSpecial
GoTo nextCell
End Select
End If
Next i
noMatchFound:
MsgBox "......" 'Message appears only when no match was found in column A, column B and column C + D
nextCell:
Next cell
Application.ScreenUpdating = True
I hope you don't mind my saying so, but your code is hard to follow, including your choice of variable names. I can recommend that if you do not make use of your .copy statements, then comment them out and your code will run much faster.
Let's assume I have in xls a range filled like this:
ROW 1 |1|s|d|f|g|
ROW 2 |2|d|k|o|p|
ROW 3 |1|a|x|y|z|
I already have the code (vba) to work (parse data) on each row and put it into a txt file, but I'm not able to work only with rows that have, for example, "1" in the first column.
Almost tried most of the suggestion here posted without any luck...
Private Sub CommandButton1_Click()
lastRow = ActiveSheet.Range("B" & Rows.Count).End(xlUp).Row
SetValSrcNat = ""
Set fs = CreateObject("Scripting.FileSystemObject")
On Error GoTo fileexists
Set stream = fs.CreateTextFile("C:\Users\luciano.vigano\Documents \prova.txt", False, True)
For elabrow = 6 To lastRow
valInterface = Cells(elabrow, 3).Value
valProto = Cells(elabrow, 8).Value
valSrc = Cells(elabrow, 9).Value
If valSrc = "host" Then
valSrc = Cells(elabrow, 10)
Else
valSrc = Cells(elabrow, 9).Value & " " & Cells(elabrow, 10)
End If
valSrcNat = Cells(elabrow, 11).Value
If valSrcNat = "" Then
valSrcNat = SetValSrcNat
Else
valSrcNat = Cells(elabrow, 11).Value
End If
stream.Write ("Rule" & valRuleNumber & Chr(13) & Chr(10))
stream.WriteLine valInterface
Next elabrow
stream.Close
fileexists:
If Err.Number = 58 Then
MsgBox "File already Exists"
End If
End Sub
I have racked my brain for to long on this simple problem that I cannot figure it out at this point.
The situation:
I have 2 columns, D and I. Column D is filled down to X# of rows.
I need to search for a string on each cell in D:X cell and based on the IF loop assign a value to I:X cell
The problem:
With each loop the value that is stored in the cells I-1 through I-X is updating with the most current value. So at the end of the third loop the values in I1-I3 are all Unknown. Any help is appreciated.
Old Code
Sub Country()
'Variables
Lastrow = Worksheets("SFDC").UsedRange.Rows.Count
lastrow2 = Worksheets("SFDC").UsedRange.Rows.Count
'check the rows for values
If lastrow2 > 1 Then
lastrow2 = 0
Else
End If
'Code will run until the last value it reached
Do While lastrow2 <> Lastrow
Set Check = Range("D2:D" & Lastrow)
For Each Cell In Check
If InStr(Cell, "ANZI-") Then
Range("I2:I" & cellvalue).Value = "ANZI"
lastrow2 = lastrow2 + 1
ElseIf InStr(Cell, "US-") Then
Range("I2:I" & cellvalue).Value = "US"
lastrow2 = lastrow2 + 1
Else
Range("I2:I" & cellvalue).Value = "Unknown"
lastrow2 = lastrow2 + 1
End If
Next
Loop
End Sub
New Code, Now the values are changing but its only being assigned to the initial cell I:2. But if I add +1 to the cellvalue like the previous codethen it still overwrites the previous values.
Sub Country()
'Variables
lastrow = Worksheets("SFDC").UsedRange.Rows.Count
'Code will run until the last value it reached
Set Check = Range("D2:D" & lastrow)
cellvalue = 2
For Each Cell In Check
If InStr(Cell, "ANZI-") Then
Range("I2:I" & cellvalue).Value = "ANZI"
ElseIf InStr(Cell, "US-") Then
Range("I2:I" & cellvalue).Value = "US"
Else
Range("I2:I" & cellvalue).Value = "Unknown"
End If
cellvalue = cellvalue + 1
Next
End Sub
just remove the Do...Loop because the For...Next is already doing the job for you. And, besides, it is better to do lastrow2 < Lastrow + 1 instead of lastrow2 <> Lastrow
I'm so dumb.
Sub Country()
'Get # of rows on worksheet
lastrow = Worksheets("SFDC").UsedRange.Rows.Count
'Setting variable for the For Loop
Set Check = Range("D2:D" & lastrow)
'will be used as a counter for the cell the return will be placed
cellvalue = 2
'Code will run until through each cell until the last value it reached
For Each Cell In Check
'if the string is in the D cell then the value will be written to the I cell
If InStr(Cell, "ANZI-") Then
Cells(cellvalue, "I") = "ANZI"
ElseIf InStr(Cell, "US-") Then
Cells(cellvalue, "I") = "US"
Else
Cells(cellvalue, "I") = "Unknown"
End If
cellvalue = cellvalue + 1
Next
End Sub
Just noticed that you got your answer but since I have already worked on, this is for your reference.
Option Explicit
Sub Country()
Dim lastRow As Long
Dim Check As Range
Dim rowNum As Long
Dim cell
'Get # of rows on worksheet
lastRow = Worksheets("SFDC").UsedRange.Rows.Count
'Setting variable for the For Loop
Set Check = Range("D2:D" & lastRow)
'will be used as a counter for the cell the return will be placed
'Code will run until through each cell until the last value it reached
For Each cell In Check
rowNum = cell.Row()
'if the string is in the D cell then the value will be written to the I cell
If InStr(cell, "ANZI") Then
Range("I" & rowNum) = "ANZI"
ElseIf InStr(cell, "US") Then
Range("I" & rowNum) = "US"
Else
Range("I" & rowNum) = "Unknown"
End If
Next
End Sub
I am new to Excel VBA and I really need your help. I have a code that will look for the duplicate values in Column A. This code will highlight the duplicate values. I want:
1.) This code to ONLY run when I click on a button.
2.) I would like to have (somewhere in the same worksheet), the number of duplicate results and a hyper link that when you click on it will direct you the duplicate result (this is because I have sometimes huge files that I need to validate). Here is the code I currently have:
Sub Worksheet_Change(ByVal Target As Excel.Range)
Dim C As Range, i As Long
If Not Intersect(Target, Me.[A:A]) Is Nothing Then
Application.EnableEvents = False
For Each C In Target
If C.Column = 1 And C.Value > "" Then
If WorksheetFunction.CountIf(Me.[A:A], C.Value) > 1 Then
i = C.Interior.ColorIndex
f = C.Font.ColorIndex
C.Interior.ColorIndex = 3 ' Red
C.Font.ColorIndex = 6 ' Yellow
C.Select
MsgBox "Duplicate Entry !", vbCritical, "Error"
C.Interior.ColorIndex = i
C.Font.ColorIndex = f
End If
End If
Next
Application.EnableEvents = True
End If
End Sub
I would really appreciate it if you help me with this.
Add the code to Module1 Alt+F11
Option Explicit
Sub MyButton()
Dim RangeCell As Range, _
MyData As Range
Dim MyDupList As String
Dim intMyCounter As Integer
Dim MyUniqueList As Object
Dim lngLastRow As Long, lngLoopRow As Long
Dim lngWriteRow As Long
Set MyData = Range("A1:A" & Cells(Rows.Count, "A").End(xlUp).Row)
Set MyUniqueList = CreateObject("Scripting.Dictionary")
Application.ScreenUpdating = False
MyDupList = "": intMyCounter = 0
'// Find Duplicate
For Each RangeCell In MyData
If RangeCell <> "V" And RangeCell <> "R" Then
If Evaluate("COUNTIF(" & MyData.Address & "," & RangeCell.Address & ")") > 1 Then
'// Color. Change to suit RGB(141, 180, 226).
RangeCell.Interior.Color = RGB(141, 255, 226)
If MyUniqueList.exists(CStr(RangeCell)) = False Then
intMyCounter = intMyCounter + 1
MyUniqueList.Add CStr(RangeCell), intMyCounter
If MyDupList = "" Then
MyDupList = RangeCell
Else
MyDupList = MyDupList & vbNewLine & RangeCell
End If
End If
Else
RangeCell.Interior.ColorIndex = xlNone
End If
End If
Next RangeCell
'// Move duplicate from Column 1 to Column 7 = (G:G)
lngWriteRow = 1
lngLastRow = Cells(Rows.Count, 1).End(xlUp).Row
For lngLoopRow = lngLastRow To 1 Step -1
With Cells(lngLoopRow, 1)
If WorksheetFunction.CountIf(Range("A1:A" & lngLastRow), .Value) > 1 Then
If Range("G:G").Find(.Value, lookat:=xlWhole) Is Nothing Then
Cells(lngWriteRow, 7) = .Value
lngWriteRow = lngWriteRow + 1
End If
End If
End With
Next lngLoopRow
Set MyData = Nothing: Set MyUniqueList = Nothing
Application.ScreenUpdating = False
If MyDupList <> "" Then
MsgBox "Duplicate entries have been found:" & vbNewLine & MyDupList
Else
MsgBox "There were no duplicates found in " & MyData.Address
End If
End Sub
.
Add Module
Add Button
Assign to Macro
I am trying to search for a persons' name within another Range.Find but I keep getting Run-Time Error 91 - Object variable or With block variable not set.
Something happens to "rngFound" within "getPaid".
Sub EmailClick()
Dim lastSeasonRow As Double
lastSeasonRow = Worksheets("Season 2014-2015").Range("A" & Worksheets("Season 2014-2015").Rows.Count).End(xlUp).Row
Dim lastSeasonEmailRow1 As Double
lastSeasonEmailRow1 = Worksheets("Email").Range("A" & Worksheets("Email").Rows.Count).End(xlUp).Row
Dim rng As Range
Dim rngFound As Range
Dim getPaid As Range
Dim ErrorEmail As String
Dim colMyCol As New Collection 'Our collection
For j = 2 To lastSeasonRow
Set rng = Worksheets("Email").Range("A2:A" & lastSeasonEmailRow1)
Set rngFound = rng.Find(Worksheets("Season 2014-2015").Cells(j, 1).Value)
If Not rngFound Is Nothing Then
' If its Found
If DoesItemExist(colMyCol, rngFound.Offset(0, 1).Value) = False Then
'Check If Already completed swimmer's family
Dim CountSwimmers As String
CountSwimmers = Application.CountIf(Worksheets("Email").Range("C2:C" & lastSeasonEmailRow1), rngFound.Offset(0, 2).Value)
If CountSwimmers > 1 Then
For s = 1 To CountSwimmers
If s = 1 Then
'If first swimmer
Set rng = Worksheets("Email").Range("C2:C" & lastSeasonEmailRow1)
Set rngFound = rng.Find(rngFound.Offset(0, 2).Value)
Debug.Print rngFound.Offset(0, -2).Value
Set rngBFound = rngFound
Else
'Next swimmer in family
Set rngFound = rng.FindNext(rngFound)
Debug.Print rngFound.Offset(0, -2).Value
********************** When Debugging, above line is Highlighted.
End If
********************************' TODO: Grab Worksheet's Name with persons' name and get Money column**
Set getPaid = Worksheets("Season 2014-2015").Range("A2:A" & lastSeasonRow).Find(rngFound.Offset(0, -2).Value)
If Not getPaid Is Nothing Then
'If its found
If getPaid.Offset(0, 14).Value <> "" Then
'If they do owe money
Debug.Print getPaid.Offset(0, 14).Value
Else
End If
End If
Next s
'write name to list, if name in array skip it, when lastSeasonRow, remove array.
colMyCol.Add (rngFound.Offset(0, -1).Value)
'TODO: change values below to strings that will correspond with aboves combined values
If rngFound.Value = "Michael" Then
Call Send_Email_Using_VBA(rngFound.Offset(0, 2).Value, rngFound.Offset(0, 1).Value, rngFound.Value, Worksheets("Season 2014-2015").Cells(j, 15).Value)
End If
Else
Debug.Print rngFound.Value
If Worksheets("Season 2014-2015").Cells(j, 15).Value <> "" Then
'If they do owe money
If rngFound.Offset(0, 3).Value <> "" Then
'if multiple emails (primary and cc)
If rngFound.Value = "Michael" Then
Call Send_Email_Using_VBA(rngFound.Offset(0, 2).Value, rngFound.Offset(0, 1).Value, rngFound.Value, Worksheets("Season 2014-2015").Cells(j, 15).Value, rngFound.Offset(0, 3).Value)
End If
Else
If rngFound.Value = "Michael" Then
Call Send_Email_Using_VBA(rngFound.Offset(0, 2).Value, rngFound.Offset(0, 1).Value, rngFound.Value, Worksheets("Season 2014-2015").Cells(j, 15).Value)
End If
End If
End If
End If
End If
Else
ErrorEmail = ErrorEmail + Worksheets("Season 2014-2015").Cells(j, 1).Value + vbNewLine
End If
Next j
If ErrorEmail <> "" Then
MsgBox ("No Email Found For: " & vbNewLine & ErrorEmail)
End If
End Sub
Thank You
EDIT: Added Images for data reference:
Email Worksheet
Season 2014-2015 WorkSheet
For this proposed solution, you will need to change the getPaid variable to type long and add a variable (e.g. gotPaid) of type double.
Dim getPaid As Long, gotPaid As Double
Change the following section of code.
Set getPaid = Worksheets("Season 2014-2015").Range("A2:A" & lastSeasonRow).Find(rngFound.Offset(0, -2).Value)
If Not getPaid Is Nothing Then
'If its found
If getPaid.Offset(0, 14).Value <> "" Then
'If they do owe money
Debug.Print getPaid.Offset(0, 14).Value
Else
End If
End If
To this.
With Worksheets("Season 2014-2015")
gotPaid = Application.SumIfs(.Columns("O"), .Columns("A"), rngFound.Offset(0, -2).Value)
getPaid = Application.CountIfs(.Columns("A"), rngFound.Offset(0, -2).Value)
If CBool(getPaid) Then
'If its found
If CBool(gotPaid) Then
'If they do owe money
Debug.Print rngFound.Offset(0, -2).Value & ": " & gotPaid
Else
End If
End If
End With
By shuffling off the second find operation, you are not redefining the first and the .FindNext should keep operating until you meet the CountSwimmers number. Alternately you could do this by not reusing the same variables but the worksheet functions should work well here.
Due to your speciality helper functions like DoesItemExist this could not be tested but it does compile.