Finding and storing an address of a cell with value<=x - vba

I was wondering if someone would be kind enough to suggest some corrections to the indicated line in the script below.
It is throwing up "Object variable or With block variable not set" alarm.
I can only guess this means the "CellFound" range is not being set and that the problem lies within that line.
The "CellFound" variable is meant to find and store the location of a cell.value<=25 within DateRng for use by the following condition
To re-iterate, the entire script is to carry out the following tasks:
Locate a range that is located between 2 cells containing specific strings (DateRng)
Loop within this range for cells (i) that have a value <=25
Compare two other cells which are offset to "i"
Export a range of rows centered around "i" to different sheets pending the outcome of the above condition.
Thanks for your time.
Sub ReportCells()
Dim LR As Long, i As Long
Dim j, k As Long
Dim StartDate, FinishDate As String
Dim Sh As Worksheet: Set Sh = Sheets("Full chart and primary cals")
Dim CellFound As Range
'Range Extraction Script
'Search location and values
LookupColumn = "B"
StartDate = "2013.01.02 20:00"
FinishDate = "2013.01.09 20:00"
'Find Lower Limit
For j = 1 To 30000
If Sh.Range(LookupColumn & j).Value = FinishDate Then FinishDateRow = j
Next j
'Find Upper Limit
For k = FinishDateRow To 1 Step -1
If Sh.Range(LookupColumn & k).Value = StartDate Then StartDateRow = k - 1
Next k
'Set Range once located
Dim DateRng As Range: Set DateRng = Sh.Range(LookupColumn & StartDateRow & ":" & LookupColumn & FinishDateRow)
MsgBox DateRng.Address
'Find Cell
With DateRng
LR = Range("B" & Rows.Count).End(xlUp).Row
For i = 1 To LR
** Set CellFound = .Find(Sh.Range("M:M").Value <= 25, LookIn:=xlValues) **
MsgBox CellFound.Address
If Not CellFound Is Nothing And CellFound.Offset(0, -5).Value < CellFound.Offset(-1, -5).Value Then .Offset(-3, 0).Resize(10, 1).EntireRow.Copy Destination:=Sheets("DownT").Range("A" & Rows.Count).End(xlUp).Offset(2)
If Not CellFound Is Nothing And CellFound.Offset(0, -5).Value > CellFound.Offset(-1, -5).Value Then .Offset(-3, 0).Resize(10, 1).EntireRow.Copy Destination:=Sheets("UpT").Range("A" & Rows.Count).End(xlUp).Offset(2)
Next i
End With
End Sub
EDIT: The cell selection and copy block has been modified to the code below. It seems that the value<=25 set range commands are not executing as they should be. They are definately filtering data but on what column I am not sure. The block is returning a range of cells of the correct size. But only one range (instead of around 20 or so). And of the wrong range of rows :S I guess any progress is progress regardless of if it's right or wrong
With Sheets("Full chart and primary cals")
LR = Range("B" & Rows.Count).End(xlUp).Row
'For i = Range("M" & Rows.Count).End(xlUp).Row To 1 Step -1
For i = 1 To LR
With DateRng.Range("M" & i)
If Range("M" & i).Value <= 25 Then Set CellFound = Sh.Range("M" & i)
If Not CellFound Is Nothing Then .Offset(-5, 0).Resize(10, 1).EntireRow.Copy Destination:=Sheets("DownT").Range("A" & Rows.Count).End(xlUp).Offset(2)
End With
Next i
End With

The solution to the problem........
'Loop through sheet looking for cells
LR = .Range("B" & Rows.Count).End(xlUp).Row
For i = 10 To LR
'Find cells in "M" and store thier reference in Cellref
If .Range("M" & i).Value <= 25 Then Set Cellref = .Range("M" & i) Else Set Cellref = .Range("Z15")
'Find if Cell ref is contained within DateRange and store result as bool
If Not Application.Intersect(DateRange, Cellref) Is Nothing Then iSect = True Else iSect = False
'Output cell ranges to the appropriate sheets
If iSect = True And Cellref.Offset(0, -5) < Cellref.Offset(-10, -5) Then _
Cellref.Offset(-3, 0).Resize(10, 1).EntireRow.Copy Destination:=Sheets("DownT").Range("A" & Rows.Count).End(xlUp).Offset(2)
If iSect = True And Cellref.Offset(0, -5) > Cellref.Offset(-10, -5) Then _
Cellref.Offset(-3, 0).Resize(10, 1).EntireRow.Copy Destination:=Sheets("UpT").Range("A" & Rows.Count).End(xlUp).Offset(2)
Next i

From what I can tell from your code you're misusing the Range.Find() function, which will most probably cause it to return Nothing instead of a meaningful range.
Sh.Range("M:M").Value will throw a Type Mismatch error as you cannot use the .Value property of a Range containing multiple cells. As this error is contained within the arguments of your .Find function it's entirely possibly it's just being ignored but it will still cause .Find to return Nothing.
Even were that not the case Sh.Range("A1") <= 25 evaluates to either True or False (Depending on the value of A1) and the Find function would then search DateRng for the first instance of True or False within that range.
I'd recommend some further reading on how the Range.Find function works as it may not be suitable for the task you have in mind.

Related

Behavior of Cell.Offset versus ActiveCell.Offset in VBA

I have a For loop & a For Each loop in VBA, where I am searching for a string within the content of each cell in the loop using Offset:
Using For Each:
Lastrow = ActiveSheet.Range("A2").End(xlDown).Row
Set Myrange = ActiveSheet.Range("M2:M" & Lastrow)
countrows = Cells(Cells.Rows.Count, "A").End(xlUp).Row
For Each Cell In Myrange
If strPattern <> "" Then
If Cell.Offset(0, 31) <> "Fizz" Then
strInput = Cell.Value
Using For:
countrows = Cells(Cells.Rows.Count, "A").End(xlUp).Row
For i = 1 To countrows
Range("AK" & i).Select
check_value = ActiveCell
If ActiveCell.Offset(0, 7) <> "Buzz" Then
ActiveCell.EntireRow.Copy
In the bottom example, I must use ActiveCell.Offset. Using Cell.Offset or even Cell.Offset.Value throws an "Object Required" error.
Why is this the case?
In the bottom example you haven't defined what Cell is so VBA has no clue as to what you're trying to do. Cell isn't a special word - it is a variable in the top example
A better way to write your bottom statement would be to use a With instead of the ActiveCell and Select
countrows = Cells(Cells.Rows.Count, "A").End(xlUp).Row
For i = 1 To countrows
With Range("AK" & i)
check_value = .Value2
If .Offset(0, 7) <> "Buzz" Then
.EntireRow.Copy
End If
End With
Next i
In first loop Cell is a Range object.
In second one Cell is Nothing, you must assign a Range object to it i.e.:
Set Cell = Range("AK" & i)
Btw, do you declare your variables?

VBA SUMIFS - Not Working, All Inputs Return Correct Values

The following code is throwing an 1004 runtime error when I go to run. The debugger highlights the SUMIFS function in just above part 2.
The goal of this sub is to locate duplicate rows using columns 1, 3, and 5 as "primary-keys" and then combine values by column for rows 6-7 and 10-17 based off those values for each row. Hence the SUMIFS.
I'm confused. Using the immediate window I can return the correct values for each section of the SUMIFS fuction (ws.Cells(lRow, lCol).Select will select the correct cell, etc.). My next thought was that the ranges were not interpreted correctly by the SUMIFS so I popped the same function, using specific ranges, into the immediate window and received the same error. See line below for immediate window entry - note that the goal is to combine values between rows 21:23 in this example.
debug.Print application.WorksheetFunction.SumIfs(range("F21:F23"), range("A9:A30"), range("A21").Value, range("C9:C30"), range("C21").Value, range("E9:E30"), range("E21").Value)
I'm assuming, and 100% sure, that named ranges, .codenames, and variables are working as desired. That said, I've been mistaken before.
Any help would be greatly appreciated.
Private Sub dba_combine_rows()
Const COL_TRIPS = 6
Const COL_EMP_TRIP = 7
Const COL_LN_HC = 10
Const COL_USN_PR = 17
Dim lLastRow As Long
Dim ws As Worksheet
Set ws = DBA
Dim answer As Integer
answer = MsgBox("Are you sure you want to combine rows?", vbYesNo, "Combine Rows")
If answer = vbNo Then
Exit Sub
End If
'Get the last row
Dim i As Long
For i = Range("inputRange" & ws.CodeName).Column To (Range("inputRange" & ws.CodeName).Column + Range("inputRange" & ws.CodeName).Columns.Count - 1)
If ws.Cells(ws.Rows.Count, i).End(xlUp).Row > lLastRow Then
lLastRow = ws.Cells(ws.Rows.Count, i).End(xlUp).Row
End If
Next i
''Combine, start modify
'Set aliases for columns A & B & C, used for checking duplicates
Dim rngA As Range, rngB As Range, rngC As Range
Set rngA = ws.Range("inputRange" & ws.CodeName).Columns(1)
Set rngB = ws.Range("inputRange" & ws.CodeName).Columns(3)
Set rngC = ws.Range("inputRange" & ws.CodeName).Columns(5)
Dim lRow As Long, lCol As Long, strHolderA As String, lHolderR As Long
For lRow = ws.Range("inputRange" & ws.CodeName).Row To lLastRow
'Part 1 - Check for duplicate entity-country
If Application.CountIfs(rngA, ws.Cells(lRow, rngA.Column), rngB, ws.Cells(lRow, rngB.Column), rngC, ws.Cells(lRow, rngC.Column)) > 1 Then
strHolderA = (ws.Cells(lRow, rngA.Column).Value & ws.Cells(lRow, rngB.Column).Value & ws.Cells(lRow, rngC.Column).Value)
lHolderR = lRow
For lCol = COL_TRIPS To COL_USN_PR
If lCol = COL_EMP_TRIP Then
lCol = COL_LN_HC
End If
ws.Cells(lRow, lCol).Value = Application.WorksheetFunction.SumIfs( _
ws.Range(Col_Letter(lCol) & lRow & ":" & Col_Letter(lCol) & lLastRow), rngA, ws.Cells(lRow, rngA.Column).Value, rngB, ws.Cells(lRow, rngB.Column).Value, rngC, ws.Cells(lRow, rngC.Column).Value)
Next lCol
'Part 2 - Delete similar rows, excluding 1st
Dim lRow2 As Long
For lRow2 = ws.Range("inputRange" & ws.CodeName).Row To lLastRow
If (ws.Cells(lRow2, rngA.Column).Value & ws.Cells(lRow2, rngB.Column).Value & _
ws.Cells(lRow2, rngC.Column).Value) = strHolderA And lRow2 <> lHolderR Then
Rows(lRow2 & ":" & lRow2).Select
Selection.Delete Shift:=xlUp
lRow2 = lRow2 - 1
End If
Next lRow2
End If
Next lRow
End Sub
The sum_range parameter (the first one) has to be the same size as the criteria ranges, which all. also, have to be the same size.
"F21:F23" is just 3 cells, while the others i.e. "A9:A30" count 22 cells each.

Clear content of a range if cell contains a specific text

I want to make a macro that clears the content of the cells in the blue border (~40.000 Rows) when the cells in the red border (column AX) contain the text "NoBO" (=No Backorder) without losing the formulas in the columns AP:AX.
Sub clear_ranges()
Dim ws As Worksheet
Dim x As Integer
Dim clearRng As Range
Application.ScreenUpdating = False
Set ws = ThisWorkbook.Sheets("Input")
For x = 6 To ws.Range("B" & Rows.Count).End(xlUp).Row
If (ws.Range("AX6" & x).Value = "NoBO") Then
If clearRng Is Nothing Then
Set clearRng = ws.Range("B6" & x & ":" & "AN6" & x)
Else
Set clearRng = Application.Union(clearRng, ws.Range("B6" & x & ":" & "AN6" & x))
End If
End If
Next x
clearRng.Clear
End Sub
And for some reason:
For x = 6 To ws.Range("B" & Rows.Count).End(xlUp).Row
gives me a error "Overflow". After searching I know what this error means but I can't find a solution for this.
tl;dr - I want to delete the range B6:B##### (till last row) to AN6:AN####*(till last row) if cell AX##### containts NoBO
It is too easy to get an overflow using Integer. Replace:
Dim x As Integer
with:
Dim x As Long
Try:
Sub clear_ranges()
Dim ws As Worksheet
Dim x As Integer
Dim clearRng As Range
Application.ScreenUpdating = False
Set ws = ThisWorkbook.Sheets("Input")
For x = 6 To ws.Range("B" & Rows.Count).End(xlUp).Row
If ws.Range("AX" & x).Value = "NoBO" Then
ws.Range("B" & x & ":" & "AN" & x).Clear
End If
Next x
Application.ScreenUpdating = True
End Sub
I think the Union function can only store up to 30 ranges so it might not suit your needs.
Hi if you are Deleting Rows it's the Best to use a For Each Loop or start from the bottom of the column and work up.
'Loop through cells A6:Axxx and delete cells that contain an "x."
For Each c In Range("AX6:A" & ws.Range("B" & Rows.Count).End(xlUp).Row)
If c.Value2 = "NoBo" Then
Set clearRng = ws.Range("B" & c.Row & ":" & "AN" & c.Row)
End If
clearRng.Clear
Next
try this
Option Explicit
Sub clear_ranges()
Dim ws As Worksheet
Application.ScreenUpdating = False
Set ws = ThisWorkbook.Sheets("Input")
With ws
With .Range("B5:AX" & .Cells(.Rows.Count, "B").End(xlUp).Row) 'take all data
.AutoFilter Field:=49, Criteria1:="NoBO" 'filter to keep only rows with "NoBO" in column "AX" (which is the 49th column from column "B"
With .Offset(1).Resize(.Rows.Count - 1) 'offset from headers
If Application.WorksheetFunction.Subtotal(103, .Columns(1)) > 0 Then Intersect(.SpecialCells(xlCellTypeVisible), ws.Columns("B:AN")).ClearContents 'clear cells in columns "B:AN" of filtered rows
End With
.AutoFilter 'remove autofilter
End With
End With
Application.ScreenUpdating = True
End Sub
You can try
Assuming that there are no blank cells in AX Column
Sub clr_cell()
For i = 6 To ActiveSheet.Range("AX6", ActiveSheet.Range("AX6").End(xlDown)).Rows.Count
'counts the no. of rows in AX and loops through all
If ActiveSheet.Cells(i, 50).Value = "NoBo" Then
ActiveSheet.Range(Cells(i, 2), Cells(i, 40)).ClearContents
'clears range B to AN
End If
Next i
End Sub
I tested this on 40k rows and it worked fine. It takes a while to execute due to the no. of rows maybe.

Trying to Add a Vlookup Piece to my Excel Macro

I'm trying to add a Vlookup piece to a long macro that I'm working on to eliminate some daily data manipulation work.
Essentially everyday I have four new columns of data that I compare to the day befores, using vlookup. The four new columns sit in columns C-F and the old data in columns M-P. I vlookup column D against column M, with the formula in column G.
I'm running into a problem of how to be flexible with the range I give the macro to use each day as I don't want to constantly change it. The amount of rows will fluctuate between 10,000-30,000.
Here is my code- I'm probably thinking about this all wrong.
Sub Lookup()
Dim i, LastRow
Set i = Sheets("data").Range("F5").End(xlUp)
If Cells(i, "F5").Value <> "" Then
Range(i, "G").Value = WorksheetFunction.VLookup(Cells(i, "D"), Range("N").End(xlDown), 1, False)
End If
End Sub
Give this a go
Sub Sheet2_Button1_Click()
Dim Rws As Long, rng As Range, Mrng As Range, x
Rws = Cells(Rows.Count, "D").End(xlUp).Row
Set rng = Range(Cells(1, "G"), Cells(Rws, "G"))
Set Mrng = Range("M1:M" & Rws)
rng = "=IFERROR(VLOOKUP(D1, " & Mrng.Address & ",1,0),""Nope"")"
'----------If you want it to be just values uncomment the below line--------------
' rng.Value=rng.Value
End Sub
You have some backwards range references. I can't speak to the vlookup call, but you can start by looking at this part:
If Cells(i, "F5").Value <> "" Then
Range(i, "G").Value = WorksheetFunction.VLookup(Cells(i, "D"), Range("N").End(xlDown), 1, False)
End If
Try changing it to this to fix the range declarations:
If Range("F" & i).Value <> "" Then
Range("G" & i).Value = WorksheetFunction.VLookup(Range("D" & i), Range("N").End(xlDown), 1, False)
End If

Delete blank row using For Next

I have a problem with my code about delete blank rows. It just has to delete some rows not all blank rows and rows value "0". I don't wanna use .SpecialCells(xlCellTypeBlanks) as some threat on SO forum.
Dim R As Integer
R = Range("CuoiNKC").Row - 1
Dim DelCell As Range
Dim DelRange As Range
Set DelRange = Range("J9:J" & R)
For Each DelCell In DelRange
If DelCell.Value = "0" Or DelCell.Formula = Space(0) Then
DelCell.EntireRow.Delete
End If
Next DelCel
Why don't you use Range AutoFilter Method instead of looping.
Assuming you have the correct value of DelRange in your code, try this:
DelRange.AutoFilter 1, AutoFilter 1, "=0", xlOr, "=" 'filtering 0 and space
DelRange.SpecialCells(xlCellTypeVisible).EntireRow.Delete xlUp 'delete visible cells
ActiveSheet.AutoFilterMode = False 'remove auto filter mode
Btw, if you want to stick with your logic, you need to iterate the rows backward.
You can only do that using the conventional For Next Loop. Again assuming value of R is correct.
For i = R To 9 Step -1
If Range("J" & i).Value = "0" Or Range("J" & i).Value = " " Then
Range("J" & i).EntireRow.Delete xlUp
End If
Next