Despite reading several threads searching for answers to similar problems I have been unable to debug my code on its own.
I am trying to write a macro that will search all cells between AE and BF for the term "Aeronautics Engineers" and then copy all rows that contain that term to a new sheet. The entire sheet has a total of 99289.
I have tried using the following code without any luck:
Sub MoveAero()
Dim strArray As Variant
Dim wsSource As Worksheet
Dim wsDest As Worksheet
Dim NoRows As Long
Dim DestNoRows As Long
Dim I As Long
Dim J As Integer
Dim rngCells As Range
Dim rngFind As Range
Dim Found As Boolean
strArray = Array("Aeronautic")
Set wsSource = ActiveSheet
NoRows = wsSource.Range("A65536").End(xlUp).Row
DestNoRows = 1
Set wsDest = ActiveWorkbook.Worksheets.Add
For I = 1 To NoRows
Set rngCells = wsSource.Range("AE" & I & ":BF" & I)
Found = False
For J = 0 To UBound(strArray)
Found = Found Or Not (rngCells.Find(strArray(J)) Is Nothing)
Next J
If Found Then
rngCells.EntireRow.Copy wsDest.Range("A" & DestNoRows)
DestNoRows = DestNoRows + 1
End If
Next I
End Sub
Thanks for any assistance!
Your problem is in your j loop:
For J = 0 To UBound(strArray)
The UpperBound (Ubound) of array strArray is 0. It's an array with a single element "Aeronautic".
So your loop is looping once and exiting.
Instead try looping through your range:
For Each rngCell in rngCells.Cells
if rngCell.value = "Aeronatic" Then
Found = True
Exit For
End if
Next rngCell
Here we loop through that rngCells range that you just made, cell by cell. Then we test if if the cell has the value you are looking for. If we find it, we set found to true and exit the for loop. You don't have to exit the for loop, but we found what we wanted, so there is no reason not to save some cpu time.
Full code, removed unnecessary variables and moved a little bit around:
Sub MoveAero()
Dim wsSource As Worksheet
Dim wsDest As Worksheet
Dim NoRows As Long
Dim DestNoRows As Long
Dim I As Long
Dim J As Integer
Dim rngCells As Range
Dim rngCell as Range
Set wsSource = ActiveSheet
NoRows = wsSource.Range("A65536").End(xlUp).Row
DestNoRows = 1
Set wsDest = ActiveWorkbook.Worksheets.Add
For I = 1 To NoRows
Set rngCells = wsSource.Range("AE" & I & ":BF" & I)
For Each rngCell in rngCells.Cells
if rngCell.value = "Aeronatic" Then
'Moved this logic up from the IF block below
rngCells.EntireRow.Copy wsDest.Range("A" & DestNoRows)
DestNoRows = DestNoRows + 1
Exit For
End if
Next rngCell
Next I
End Sub
Alternatively, you could use that .find method of the range object instead of the second For loop. (Using both for your needs is unnecessary).
Sub MoveAero()
Dim wsSource As Worksheet
Dim wsDest As Worksheet
Dim NoRows As Long
Dim DestNoRows As Long
Dim I As Long
Dim rngCells As Range
Set wsSource = ActiveSheet
NoRows = wsSource.Range("A65536").End(xlUp).Row
DestNoRows = 1
Set wsDest = ActiveWorkbook.Worksheets.Add
For I = 1 To NoRows
Set rngCells = wsSource.Range("AE" & I & ":BF" & I)
'Try to find your search term in the range
If Not (rngCells.Find("Aeronautic") Is Nothing) Then
rngCells.EntireRow.Copy wsDest.Range("A" & DestNoRows)
DestNoRows = DestNoRows + 1
End If
Next I
End Sub
Related
In the code below, I have identified a range (ColRng) in which I want to check each cell - if it is empty, there is a SUMIFS function to perform. It does not work. I know my syntax and logic is horrid, but I can't figure out how to make it work.
Dim ColRng As Range
Dim LastCol As Long
Dim LastRowScenario As Long
Dim x As Long
Dim rngCrit1 As Range
Dim rngCrit2 As Range
Dim rngSum As Range
LastRowScenario = Sheets("Sheet1").Range("Q2").End(xlDown).Row
Set rngCrit1 = Sheets("Sheet1").Range("D2:D" & LastRowScenario)
Set rngCrit2 = Sheets("Sheet1").Range("B2:B" & LastRowScenario)
Set rngSum = Sheets("Sheet1").Range("Q2:Q" & LastRowScenario)
LastCol = Sheets("Summary").Range("B5").End(xlToRight).Column
Set ColRng = Range(LastCol & "6:" & LastCol & "149")
For x = ColRng.Cells.Count To 1 Step -1
With ColRng.Cells(x)
' If the cell is empty, perform a SUMIFS
If IsEmpty(.Value) Then
.Formula = Application.WorksheetFunction.SumIfs(rngSum, rngCrit1, .Range("E" & .Row).Value, rngCrit2, .Range("B" & .Row).Value)
End If
End With
Next x
Your ColRng construction is wrong - try something like this instead:
Dim ColRng As Range
Dim LastCol As Long
Dim LastRowScenario As Long
Dim x As Long
Dim rngCrit1 As Range
Dim rngCrit2 As Range
Dim rngSum As Range, ws As Worksheet, wsSumm As Worksheet
set ws = Sheets("Sheet1")
Set rngSum = ws.Range("Q2:Q" & ws.Range("Q2").End(xlDown).Row)
Set rngCrit1 = rngSum.EntireRow.Columns("D")
Set rngCrit2 = rngSum.EntireRow.Columns("B")
Set wsSumm = Sheets("Summary")
With wsSumm.Range("B5").End(xlToRight).EntireColumn
Set ColRng = wsSumm.Range(.Cells(6), .Cells(149))
End With
For x = ColRng.Cells.Count To 1 Step -1
With ColRng.Cells(x)
' If the cell is empty, perform a SUMIFS
If IsEmpty(.Value) Then
.Formula = Application.SumIfs(rngSum, _
rngCrit1, .EntireRow.columns("E").Value, _
rngCrit2, .EntireRow.columns("B").Value)
End If
End With
Next x
I am trying to hide multiple rows in an excel worksheet which are empty using following code however i am getting error message "Argument not optional". What could be wrong in the code?
Sub Attendance_Manday()
Dim sht1 As Worksheet
Dim row_count, col_count As Integer
Dim mainrange As Range
Dim startcell As Range
Set startcell = Range("B1")
Set sht1 = Sheets("Mandays")
row_count = Sheets("Mandays").Cells(Rows.Count, startcell.Column).End(xlUp).Row
col_count = Sheets("Mandays").Cells(startcell.Row, Columns.Count).End(xlToLeft).Offset(1, -2).Column
Set mainrange = sht1.Range(startcell.Address & ":" & sht1.Cells(row_count, col_count).Address)
mainrange.Range.SpecialCells(xlCellTypeBlanks).Rows.Hidden = True
End Sub
Based on your code and assuming first row in your sheet is never empty you could do something like that
Sub Attendance_Manday()
Dim sht1 As Worksheet
Dim row_count As Long, col_count As Long
Dim mainrange As Range
Dim startcell As Range
Set startcell = Range("B1")
Set sht1 = Sheets("Mandays")
row_count = Sheets("Mandays").Cells(Rows.Count, startcell.Column).End(xlUp).Row
col_count = Sheets("Mandays").Cells(startcell.Row, Columns.Count).End(xlToLeft).Offset(1, -2).Column
Set mainrange = sht1.Range(startcell.Address & ":" & sht1.Cells(row_count, col_count).Address)
Dim i As Long
For i = 1 To col_count - 1
mainrange.AutoFilter field:=i, Criteria1:="="
Next i
Dim rg As Range
Set rg = mainrange.SpecialCells(xlCellTypeVisible)
mainrange.AutoFilter
rg.Rows.EntireRow.Hidden = True
rg.Rows(1).EntireRow.Hidden = False
End Sub
An if you turn off screenupdating etc. it should be pretty fast as well
First of all thanks for your help.
I've been trying to get a dynamic list that copies values from on excel to another depending on an "IF" condition, which has worked quite fine. But I can only do it for 1 condition instead of a Range of conditions.
In excel I would usually use the COUNTIF function to see if you can find a range of values inside another range, but i am quite new to VBA and I wouldn't know how how to express this in a loop for a Range.
Example below of what has worked with one condition:
As you can see I am using "Investor" as my condition, but I need it to be for a range of values.
Thanks for your help!
LastRows = Worksheets("Data").Cells(Rows.Count, 1).End(xlUp).Row + 1
For i = 2 To LastRows
If Worksheets("Data").Range("F" & i).Value = "Investor" Then
'Instead of "Investor" I want to do something that take a list of values. Eg : If If Worksheets("Data").Range("F" & i).Value = "Range("A1:A"&LastRows) Then
Worksheets("Data").Range("A" & i).Copy
Worksheets("Email Format").Activate
LastRowEmail = Worksheets("Email Format").Cells(Rows.Count, 1).End(xlUp).Row + 1
Worksheets("Email Format").Range("A" & LastRowEmail).Select
ActiveSheet.Paste
End If
Application.Match Vs WorksheetFunction.Match
You can use one of the following Match solutions.
Option Explicit
Sub MultiCriteria1()
Dim wb As Workbook: Set wb = ThisWorkbook
Dim wsD As Worksheet: Set wsD = wb.Worksheets("Data")
Dim wsE As Worksheet: Set wsE = wb.Worksheets("Email Format")
Dim LastRowD As Long: LastRowD = wsD.Cells(wsD.Rows.Count, 1).End(xlUp).Row
Dim CurrentE As Long: CurrentE = wsE.Cells(wsE.Rows.Count, 1).End(xlUp).Row
Dim i As Long
For i = 2 To LastRowD
If Not IsError(Application.Match(wsD.Range("F" & i).Value, _
wsD.Range("A1:A" & LastRowD), 0)) Then
CurrentE = CurrentE + 1
wsE.Range("A" & CurrentE).Value = wsD.Range("A" & i).Value
End If
Next i
End Sub
Sub MultiCriteria2()
Dim wb As Workbook: Set wb = ThisWorkbook
Dim wsD As Worksheet: Set wsD = wb.Worksheets("Data")
Dim wsE As Worksheet: Set wsE = wb.Worksheets("Email Format")
Dim LastRowD As Long: LastRowD = wsD.Cells(wsD.Rows.Count, 1).End(xlUp).Row
Dim CurrentE As Long: CurrentE = wsE.Cells(wsE.Rows.Count, 1).End(xlUp).Row
Dim CurrVal As Long
Dim i As Long
For i = 2 To LastRowD
On Error Resume Next
CurrVal = WorksheetFunction.Match(wsD.Range("F" & i).Value, _
wsD.Range("A1:A" & LastRowD), 0)
If Err.Number = 0 Then
CurrentE = CurrentE + 1
wsE.Range("A" & CurrentE).Value = wsD.Range("A" & i).Value
End If
On Error GoTo 0
Next i
End Sub
This is just an example but should steer you in right direction.
Dim rngYourRange as Range
Set rngYourRange = Range("A1:C10")
Dim rngEachRange as Range
For each rngEachRange in rngYourRange 'or rngYourRange.Rows or rngYourRange.Columns
if rngEachRange.value = 1 then 'or whatever
'do what you need
end if
next rngEachRange
Can you help me correct my VBA codes. I want to convert the values of Column U until the active row to Absolute Values meaning to remove the negative amounts.
Here is my VBA code:
Sub MakeColumnsAbsoluteValue()
Dim sht As Worksheet
Dim rngToAbs As Range
Dim LastRow As Long
Dim c As Range
Set sht = ThisWorkbook.Sheets("MJEBlackline")
LastRow = sht.Cells(sht.Rows, Count, "U").End(xlUp).Row
Set rngToAbs = Range("U5:U" & LastRow)
For Each c In rngToAbs
c.Value = Abs(c.Value)
Next c
End Sub
Problem with line LastRow = sht.Cells(sht.Rows, Count, "U").End(xlUp).Row
Use of , instead of . and not specifying the sheet reference in rngToAbs
Try:
Sub MakeColumnsAbsoluteValue()
Dim sht As Worksheet
Dim rngToAbs As Range
Dim LastRow As Long
Dim c As Range
Set sht = ThisWorkbook.Sheets("FF")
LastRow = sht.Cells(sht.Rows.count, "U").End(xlUp).row
Set rngToAbs = sht.Range("U5:U" & LastRow)
For Each c In rngToAbs
c.Value = Abs(c.Value)
Next c
End Sub
You may try:
Sub MakeColumnsAbsoluteValue()
Dim sht As Worksheet
Dim rngToAbs As Range
Dim LastRow As Long
Set sht = ThisWorkbook.Sheets("MJEBlackline")
With sht
LastRow = .Cells(.Rows.Count, "U").End(xlUp).Row
Set rngToAbs = .Range("U5:U" & LastRow)
rngToAbs.Value = .Evaluate("=abs(" & rngToAbs.Address & ")")
End With
End Sub
Or even (inspired through #GarysStudent):
Sub MakeColumnsAbsoluteValue()
Dim sht As Worksheet
Dim rngToAbs As Range
Dim LastRow As Long
Set sht = ThisWorkbook.Sheets("MJEBlackline")
With sht
LastRow = .Cells(.Rows.Count, "U").End(xlUp).Row
Set rngToAbs = .Range("U5:U" & LastRow)
rngToAbs.Replace what:="-", lookat:=xlPart, replacement:=""
End With
End Sub
This would both convert the whole range in one go. Assuming that's what you meant with:
"I want to convert the values of Column U until the active row..."
You could try:
Option Explicit
Sub MakeColumnsAbsoluteValue()
Dim sht As Worksheet
Dim rngToAbs As Range, c As Range
Dim LastRow As Long, x As Long
Dim arr() As Variant
Set sht = ThisWorkbook.Sheets("MJEBlackline")
x = 0
With sht
LastRow = .Cells(.Rows.Count, "U").End(xlUp).Row
Set rngToAbs = .Range("U5:U" & LastRow)
'Loop range and create an array including all abs values
For Each c In rngToAbs
ReDim Preserve arr(x)
arr(x) = Abs(c.Value)
x = x + 1
Next c
'Paste the values of the array at once instead of pasting values one by one
.Range("U5:U" & LastRow).Value = Application.WorksheetFunction.Transpose(arr)
End With
End Sub
I have a code to copy the entire row if column B contains a certain text ("ACK-", but now I need to copy the entire row directly above the one with the certain text ("ACK-". Is this even possible? Any help will be appreciated.
Sub HEA_Filter()
Dim strArray As Variant
Dim wsSource As Worksheet
Dim wsDest As Worksheet
Dim NoRows As Long
Dim DestNoRows As Long
Dim I As Long
Dim J As Integer
Dim rngCells As Range
Dim rngFind As Range
Dim Found As Boolean
strArray = Array("ack-")
Set wsSource = ActiveSheet
NoRows = wsSource.Range("A65536").End(xlUp).Row
DestNoRows = 1
Set wsDest = Sheets("Real Alarms")
For I = 1 To NoRows
Set rngCells = wsSource.Range("B" & I)
Found = False
For J = 0 To UBound(strArray)
Found = Found Or Not (rngCells.Find(strArray(J)) Is Nothing)
Next J
If Found Then
rngCells.EntireRow.Copy wsDest.Range("A" & DestNoRows)
DestNoRows = DestNoRows + 1
End If
Next I
End Sub
To reference "the row above", you can use the Range.Offset method:
rngCells.Offset(-1).EntireRow.Copy wsDest.Range("A" & DestNoRows)
' ^^^^^^^^^^^^
However, be aware that this raised a runtime error if the range is at row 1, because row 0 does not exist. You might want to add a check for it, for example:
If rngCells.Row > 1 Then rngCells.Offset(-1).EntireRow.Copy ...