How to find the last value with specific conditions? - vba

Sheet 1 column A has the following values (it has around 3000 records. I’ve given the below sample values). I need to find the last value of a specific text.
RVT-01
RVT-02
RVT-03
RVT-04
RVT-05
RVT-06
RHT-01
RHT-02
RHT-03
RHT-04
RHT-05
ROI-01
ROI-02
ROI-03
SWO-01
SWO-02
SWO-03
SOR-01
SOR-02
SOR-03
SOR-04
SOR-05
SOR-06
SOR-07
Using VBA code
If enter short tex in sheet1.cells(2,2) = SWO , I need the last value in sheet1.cells(2,4)=SWO-03
If I enter sheet1.cells(2,2) = RHT , I need the last value in sheet1.cells(2,4)=RHT-05
If I enter sheet1.cells(2,2) = RVT , I need the last value in sheet1.cells(2,4)=RVT-06
If I enter sheet1.cells(2,2) = SOR , I need the last value in sheet1.cells(2,4)=SOR-07
What would be the VBA code for the above process?

As Skip Intro suggested, there is no need for VBA: in Column B, put a formula like this:
=IF(IF(LEFT(A1,3)=LEFT(A2,3),1,0)=0,RIGHT(TRIM(A:A),2),"") (to get the just the max number):
or
=IF(IF(LEFT(A1,3)=LEFT(A2,3),1,0)=0,A:A,"") (to get the complete contents of the cell)
Both will show you the highest values. Then you could AutoFilter that column, hiding the blanks and voila :)
Or
=IF(IF(LEFT($A1,3)=LEFT($A2,3),1,0)=0,NA(),"")
will enable you to use SpecialCells in VBA to get a range that you can interrogate for the maximum values in each group, as below:
Sub test()
Dim rng As Range
Dim cell
Range("B1:B" & Range("A65536").End(xlUp).Row).Formula = "=IF(IF(LEFT($A1,3)=LEFT($A2,3),1,0)=0,NA(),"""")"
Set rng = Range(Range("B1:B" & Range("A65536").End(xlUp).Row).SpecialCells(xlCellTypeFormulas, xlErrors).Offset(0, -1).Address)
For Each cell In rng
Debug.Print cell.Address & " =" & cell.Value
MsgBox cell.Address & " =" & cell.Value
Next
End Sub
For more information on the SpecialCells magic tricks, see How to delete multiple rows without a loop in Excel VBA.

Related

To multiply column with textbox value in vba

I have textbox1 in excel sheet and list of values in column A. As textbox is user defined, I have to multiply given value with the all the values available in column A. How it can be done using command button if I am not using a form.
rng = Evaluate(rng.Address &"*TextBox1.Value")
But is giving an error #NAME? in excel.
I got the solution and it should be
Value = Textbox1.Value
rng = Evaluate("=" & rng.Address & "*" & value)
Hope it will be useful for someone
Thanks

VBA: Give a value to blank cells in rows that meet certain criteria

Well I have done a lot of research and found a lot of relevant questions and answers but couldn't quite figure out how to cater that information to my specific need.
I am working on a project to create a macro that will correct mistakes and fill in information commonly found in product catalogs that I work with.
One thing I am trying to accomplish is to give the value "unassigned" to each blank cell in a row that is marked "Y" in column B.
I've found out how to change every cell in those particular rows and have it adjust dynamically to the number of rows. What I can't figure out is how to do the same for the number of columns. In my code below everything between columns B and S is included. Column B will always be in the same spot but column S will not always be the last column.
Dim tracked As String
Dim endCell As Range
Dim endRow As Long
Dim endColumn As Long
Dim start As Long
endRow = ActiveSheet.Range("D2").End(xlDown).Row
endColumn = ActiveSheet.Range("A1").End(xlToRight).Column
Let tracked = "B2:" & "B" & endRow
Set trackItem = ActiveSheet.Range(tracked)
For Each y In trackItem
If Left(y.Value, 1) = "Y" Then
'start = y.Row
'Set endCell = ActiveSheet.Cells(endColumn, start)
ActiveSheet.Range("B" & y.Row & ":" & "S" & endColumn).Value = "Unassigned"
End If
Next y
I included some code that I've left commented out so you can see what I've tried.
So, I can successfully change the value of all cells within that range but I need to know how to do it with a range where the number of columns will not always be the same. In addition, I want to select the blank cells only within this range and assign them a value. I imagine this will need to be done row by row as the correct criteria will not always be together.
I'm surprised more people don't use 'UsedRange' when there is a need to loop through all the cells that have data on a sheet. (Just yesterday someone was complaining that it takes too long to loop through all 17,179,869,184 cells on a worksheet...)
This example lists & counts the "used" range, and will easily adapt to your needs.
Sub List_Used_Cells()
Dim c As Range, x As Long
For Each c In ActiveSheet.UsedRange.Cells
Debug.Print c.Address & " ";
x = x + 1
Next c
Debug.Print
Debug.Print " -> " & x & " Cells in Range '" & ActiveSheet.UsedRange.Address & "' are considered 'used'."
End Sub

MS Excel VBA - Loop Through Rows and Columns (Skip if Null)

Hello stackoverflow community,
I must confess I primarily code within MS Access and have very limited experience of MS Excel VBA.
My current objective is this, I have an expense report being sent to me with deductions in another countries currency, this report has many columns with different account names that may be populated or may be null.
I currently have a Macro that will open an input box and ask for the HostCurrency/USD Exchange rate, my next step will be to start at on the first record (Row 14; Column A-K contains personal info regarding the deduction) then skip to the first deduction account (deduction accounts start at column L and span to column DG) checking if each cell is null, if it is then keep moving right, if it contains a value then I want to multiply that value by my FX rate variable that was entered in the input box, and update the cell with the converion. Once the last column (DG) has been executed I want to move to the next row (row 15) and start the process again all the way until the "LastRow" in my "Used Range".
I greatly appreciate any feedback, explanations, or links that may point me towards my goal. Thank you in advance for taking the time to read though this!
First off, you really should attempt to write the code yourself and post what you have so someone can try to point you in the right direction. If your range is going to be static this is a very easy problem. You can try something along the lines of:
Sub calcRate(rate As Double, lastrow As Integer)
Dim rng As Range
Set rng = Range("L14" & ":DG" & lastrow)
Dim c As Variant
For Each c In rng
If c.Value <> "" Then
c.Value = c.Value * rate
End If
Next
End Sub
This code will step through each cell in the given range and apply the code without the need for multiple loops. Now you can call the calcRate sub from your form where you input the rate and lastrow .
This will do it without looping.
Sub fooooo()
Dim rng As Range
Dim mlt As Double
Dim lstRow As Long
mlt = InputBox("Rate")
With ActiveSheet
lstRow = .Cells(.Rows.Count, 1).End(xlUp).Row
Set rng = .Range(.Cells(14, 12), Cells(lstRow, 111))
rng.Value = .Evaluate("IF(" & rng.Address & " <>""""," & rng.Address & "*" & mlt & ","""")")
End With
End Sub
If your sheet is static you can replace ActiveSheet with WorkSheets("YourSheetName"). Change "YourSheetName" to the name of the sheet.

putting a string from a cell into the middle of my index-match VBa script

I am trying to use the index-match formula to reorganize data such that all of the names in column J that have a matching value in column A will be placed in the same spot. I'm going to do this for 5 different columns so that the 5 names on a team will be in the same row as the name of the corresponding client.
My issue is that the index-match formula needs to be able to dynamically shorten or lengthen the size the arrays it uses based on how many clients there are when the VBA script is run.
I can dynamically determine what numbers I need in the formula using COUNTA, but the code will not compile when I try to put it in my formula. My formula is below
Range("B7").Select
ActiveCell.Formula = "=INDEX('test sheet two'!" & Range("J3") & ",MATCH(Sheet1!A5,'test sheet two'!" & Range("J1") & ",0)"
As you can see I need the strings in cells J3 and J1 to be used as the arrays for the index match. J3 = $J$2:$J$2369 and J1 = $A$2:$A$1113
When I run the code it gives me a "Application-Defined or Object-defined error."
You need to use the Range member of worksheet
so use 'test sheet two'!Range("J2:J2369") rather than 'test sheet two'!("J2:J2369").
The following runs
ActiveCell.Formula = _
"=INDEX('test sheet two'!Range(""" & Range("J3") & """) _
,MATCH(Sheet1!A5,'test sheet two'!Range(""" & Range("J1") & """),0))"
Your formula was not including the column criteria for the INDEX Function.
Try:
Range("B7").Select
ActiveCell.Formula = "=INDEX('test sheet two'!" & Range("J3") & "," & _
"MATCH(Sheet1!A5,'test sheet two'!" & Range("J1") & ",0), 1)"
Notice the additional , 1)" on the end of the formula.
Also, you do not have to first Select the cell which you want to enter the formula in, you could just use:
Range("B7").Formula =

Excel to CountIF in filtered data

I am trying to count the number of occurrences of a specific string in filtered data. I can do it using a formula in a cell but when I combine that with the other macros in my workbook the whole thing freezes.
So I would like to move the calculation to VBA so that it only calculates when the macro is run. Here is the formula that works in the cell:
=SUMPRODUCT(SUBTOTAL(3,OFFSET('2015 Master'!H:H,ROW('2015 Master'!H:H)-MIN(ROW('2015 Master'!H:H)),,1)),ISNUMBER(SEARCH("*Temp*",'2015 Master'!H:H))+0)
Basically I want to count the number of times "Temp" occurs in column H but only in the filtered data.
Thank you for your help!
ADDITION:
Here is the code I've written for the macro so far. It filters the data on a different sheet then updates the pivot table with the date range. I would like to add the count calculations to the end of this code and return the count to a cell on the 'Reporting' sheet.
Sub Button1_Click()
'Refresh the pivot table and all calculations in the active sheet
ActiveWorkbook.RefreshAll
'Gather the start and end times from the active sheet
dStart = Cells(2, 5).Value
dEnd = Cells(3, 5).Value
'Change the active sheet to the alarms database, clear all filters and then filter for the defined date range and filter for only GMP alarms
Sheets("2015 Master").Select
If ActiveWorkbook.ActiveSheet.FilterMode Or ActiveWorkbook.ActiveSheet.AutoFilterMode Then
ActiveWorkbook.ActiveSheet.ShowAllData
End If
ActiveSheet.ListObjects("Table44").Range.AutoFilter Field _
:=3, Criteria1:=">=" & dStart, Operator:=xlAnd, Criteria2:= _
"<=" & dEnd
Range("Table44[[#Headers],[GMP or non-GMP]]").Select
ActiveSheet.ListObjects("Table44").Range.AutoFilter Field:=2, Criteria1:= _
"GMP"
'Change the active sheet to the Reporting sheet
Sheets("Reporting").Select
'Within the alarms pivot table clear the label filters then filter for the date range and GMP alarms
ActiveSheet.PivotTables("PivotTable1").PivotFields("Active Time"). _
ClearLabelFilters
ActiveSheet.PivotTables("PivotTable1").PivotFields("Active Time").PivotFilters. _
Add Type:=xlDateBetween, Value1:=dStart, Value2:=dEnd
ActiveSheet.PivotTables("PivotTable1").PivotFields("GMP or non-GMP"). _
CurrentPage = "GMP"
End Sub
Pertinent to clarified question topic (i.e. " Basically I want to count the number of times "Temp" occurs in column H..."), the VBA solution can be as shown in the following code snippet. Assuming sample data entered in Column "H":
H
Temp Directory on C: Drive
Temp Directory
Project Directory
Output Temp Directory
Start Directory
Temp obj
apply the VBA Macro:
Sub CountTempDemo()
Dim i As Integer
Dim count As Integer
Dim startRow As Integer
Dim lastRow As Integer
Dim s As String
startRow = 2 'or use your "filtered range"
lastRow = Cells(Rows.count, "H").End(xlUp).Row 'or use your "filtered range"
count = 0
For i = 2 To lastRow
If InStr(Cells(i, 8).Value, "Temp") > 0 Then
count = count + 1
End If
Next
End Sub
where count value of 4 is a number of "Temp" occurrences in specified "H" range.
Hope this may help. Best regards,
To iterate over a column and find only visible (unfiltered) cells, one way is this:
Set h = ... Columns ("H");
Set r = h.SpecialCells(xlCellTypeVisible)
' now r is a composite range of potentially discontiguous cells
' -- it is composed of zero or more areas
'but only the visible cells; all hidden cells are skipped
Set ar = r.Areas
for ac = 1 to ar.Count
Set rSub = ar(ac)
'rSub is a contiguous range
'you can use a standard formula, e.g. Application.WorksheetFunction.CountIf(...)
'or loop over individual elements
'and count what you like
next
caveats: if any rows (or the column) are hidden manually (not from filtering) the count using this method will consider them as filtered (i.e. hidden/not visible).
Update: answer to comment
A Range is really a very general purpose notion of an aggregation of cells into a grouping or collecting object (the Range). Even though we usually think of a Range as being a box or rectangle of cells (i.e. contiguous cells), a Range can actually assemble discontiguous cells.
One example is when the user selects several discontiguous cells, rows, and/or columns. Then, for example, ActiveSheet.Selection will be a single Range reflecting these discontiguous cells. The same can happen with the return value from SpecialCells.
So, the Excel object model says that in general, a Range can be composed of Areas, where each Area itself is also represented by a Range, but this time, it is understood to be a contiguous Range. The only way you can tell if the Range is contiguous or not is if you created it as a box/rectangle, or, if Areas.Count = 1.
One way to investigate a bit more might be to select some discontiguous cells, then enter a macro and use the debugger to observe Selection.