excel VBA index and match functions - excel

I am trying to change excel functions into vba code. the formula below in Col AC, Row 2...
=IF(ROWS($1:1)< MATCH(0.01,H$2:H$10)+1,"",INDEX(X:X,ROWS($1:1)-MATCH(0.01,H$2:H$10)+1))
...scans the first 10 rows of Col H.
This formula looks for the first none-zero value in the rows of Col H. When it finds that row, then the values in col X will be printed out in Col AC so that the row in Col AC matches the row with the first non-zero value in Col H.
I hope that description makes sense. It works perfectly in excel worksheet. Now, i would like to change it into VBA code, here is what I have...
For i = 2 To lengthRows
With Application.WorksheetFunction
Range("AC" & i) = .IF(Rows(1) < .Match(0.01, Range("H2:H10")) + 1, "", .Index(Columns(24), Rows(1) - .Match(0.01, Range("H2:H10")) + 1))
End With
Next i
...Rows(1) is the first row and Columns(24) is Col X.
When I run the code, I am getting a run-time error mismatch '13: Type mismatch.
I am trying to understand how this previous question was answered: Excel VBA: how to solve Index and Match function type mismatch error

Taking the example from the previous answered question. You're pushing the match result into the index formula. If the match result doesn't find a match then it'll return Error 2042, which when pushed into the Index formula gives the mismatch error.
To adapt that solution for your example would be as follows:
Dim rw As Variant
With Application.WorksheetFunction
For i = 2 To lengthRows
rw = .Match(0.01, Range("H2:H10")) 'Is there a reason you're not specifying the third parameter 0 for exact match?
If Not IsError(rw) Then
Range("AC" & i) = .If(Rows(1) < .Match(0.01, Range("H2:H10")) + 1, "", .Index(Columns(24), Rows(1) - .Match(0.01, Range("H2:H10")) + 1))
Else
' Do something else if there was an error
End If
Next i
End With

I think once you want to use VBA, you need to use the VBA added capabilities, and not stick with the formula you constructed in Excel.
Since, you are looking for the first cell in Column H with a none-zero value, you can easily find it using the Application.Match, but you need to set the third parameter of match to -1 (means Greater than, looking for a match for values > 0.01).
So now, we have the row number, if you want to find the value in Column X for this row, you can use Range("AC2").Value = Range("X" & MatchRow + Rng.Item(0).Row).Value
Code
Option Explicit
Sub ConvertFormulaToVBA()
Dim MatchRow As Variant
Dim Rng As Range
Dim lengthRows As Long, i As Long
lengthRows = Cells(Rows.Count, "H").End(xlUp).Row '<-- get last row with data in Column H (in your example it's 10)
Set Rng = Range("H2:H" & lengthRows) ' <-- set the range to H2 until last row in Column H
MatchRow = Application.Match(0.01, Rng, -1) ' <-- setting the third parameter to -1, meaning greater than 0.01
If Not IsError(MatchRow) Then
Range("AC2").Value = Range("X" & MatchRow + Rng.Item(0).Row).Value
Else
' raise a message box if there is no Match
MsgBox "No none-zero value found at Range " & Rng.Address
End If
End Sub

Related

VBA - How to output a variable to a particular row and column in excel?

This code should find the correct cell (in the column corresponding to it's 'length' and the next empty row) in which to output a variable.
I'm getting the error message:
method range of object _worksheet failed
on lines 13 onward containing "outputcolumn"
In the MsgBox lines, the correct column and row number are being displayed, so I am not sure why it is not happy with my outputcolumn in particular.
Private Sub OutputRowAndColumn()
'Choose correct column: Find the length column and name this outputcolumn
Dim cell As Range, outputcolumn As Integer
Set cell = Range("FindLength").Find(Range("Length").Value, LookIn:=xlValues)
If Not cell Is Nothing Then
outputcolumn = cell.Column
End If
MsgBox "Output column is number " & outputcolumn & "."
'Choose correct row: If the cell to the left of "cell" is empty then this is the first row of output otherwise find next empty cell down
If Sheet1.Range(outputcolumn & "4").Offset(0, 1).Value = "" Then
outputrow = 4 ''' error msg '''
ElseIf Sheet1.Range(outputcolumn & "5").Offset(0, 1).Value = "" Then
outputrow = 5
Else
outputrow = Sheet1.Range(outputcolumn & "4").Offset(0, 1).End(xlDown).Row + 1
End If
MsgBox "Output row is number " & outputrow & "."
'Copy values 1, 2 and 3 from sheet 2 to sheet 1
Sheet1.Range(outputcolumn & outputrow).Offset(0, 1).Value = Sheet2.Range("Value1").Value ''' error msg '''
Sheet1.Range(outputcolumn & outputrow).Offset(0, 2).Value = Sheet2.Range("Value2").Value
Sheet1.Range(outputcolumn & outputrow).Offset(0, 3).Value = Sheet2.Range("Value3").Value
End Sub
outputcolumn is a numeric value (you defined it as Integer, but you always should define variables holding row or column numbers as long to avoid overflow errors).
So let's say outputcolumn gets the number 2 (column B). You write Sheet1.Range(outputcolumn & "4"). To access a range by it's address, You would have to write something like Range("B4"), but what you write is Range(2 & "4"), which means Range("24"), and that is an invalid address for a Range.
You could try to translate the column number 2 to a B, but there is an easier way to access a cell when you know the row and column number: Simply use the cells-property:
If Sheet1.Cells(4, outputcolumn).Offset(0, 1).Value = "" Then
' (or)
If Sheet1.Cells(4, outputcolumn+1).Value = "" Then
Just note that the order of the parameters is row, column.
"outputcolumn" is numeric in your case and when using .Range(), it needs to be a proper alphanumeric cell reference like "C5", not all numeric.
I haven't tried it directly but changing this ...
If Not cell Is Nothing Then
outputcolumn = cell.Column
End If
... to this ...
If Not cell Is Nothing Then
outputcolumn = Split(cell.Address, "$")(1)
End If
... will go a long way to helping you.

In Excel VBA, extract range text and sum data

I have a spreadsheet in which there are multiple rows that have three columns (K, L M) that contain text (inserted manually from a dropdown). The inserted text includes a 'score'. For the row shown in the image that score is 3 + 2 + 2 = 7.
What I'd like to be able to do is to have that score automatically calculated and shown in column N. I'm happy to do the score extraction given the text, but I'm completey unfamiliar with Excel's object model, and how to write a VBA macro that can be triggered across all of the rows. I assume it would be passed a range somehow, or a string designating a range, but how to do that is beyond me just now. Perhaps I just need a formula? But one that calls a function to strip non-numerical data from the cell?
Any help appreciated.
Put this formula in N2 cell and drag it all the way down.
=LEFT(K2, FIND("-", K2) - 2) + LEFT(L2, FIND("-", L2) - 2) + LEFT(M2, FIND("-", M2) - 2)
For more information see reference. It sum all numbers, that are present before the hyphen (-) in a cell.
Try:
N2 = LEFT(TRIM(K2),1) + LEFT(TRIM(L2),1) + LEFT(TRIM(M2),1)
As I said in comments, this solution does not scale so well if it is more than three columns and / or the scores are more than single digit [0-9]
A VBA solution to do all of your rows and enter the values into Column N:
Sub foo()
Dim ws As Worksheet: Set ws = Sheets("Sheet1")
'declare and set your worksheet, amend as required
LastRow = ws.Cells(ws.Rows.Count, "K").End(xlUp).Row
'get the last row with data on Column A
For rownumber = 1 To LastRow 'loop through rows
For i = 11 To 13 'loop through columns
strValue = ws.Cells(rownumber, i).Value 'get text string from cell
pos = InStr(strValue, " -") 'find the dash - in cell
If pos > 0 Then 'if dash found
Value = Value + Val(Left(ws.Cells(rownumber, i).Value, pos - 1)) 'remove everything after number
End If
Next i
ws.Cells(rownumber, 14).Value = Value 'write value to column N
Value = 0
Next rownumber
End Sub

Excel VBA Find cell address in range based on min to max for where class

Please assist me for following scenario
I need to go thorough one range and find Minimum value.If corresponding value in another range matches, then I need to find column number.
I am able to do with following code; however when there is more than one minimum value, following code always give fist minimum value column number. it is not moving to next minimum value column even if condition is not met.
it is kind of where class I am trying to apply
MyOrder = 1
Do Until wksSkill.Cells(MyRow, MyColNum).Value <> "Exclude"
MyColNum = Application.Evaluate("=CELL(""col"", INDEX(" & MyColRange.Address(0, 0) & ", MATCH(SMALL(" & MyColRange.Address(0, 0) & ", " & MyOrder & " ), " & MyColRange.Address(0, 0) & ", 0)))")
MyOrder = MyOrder + 1
Loop
First "MyColNum" value passed from another if statement, then it will take the function output. It works till the range has one minimum value.
Please assist me for any other alternative
Ok, so what I can propose, is to find min value in range, and then loop through every column in that range and check if this min value occurs there and if value "Exclude" occurs in MyRow. I have some example values in my code:
Sub mac()
Dim minVal As Double
Dim MyColRange As Range, rng As Range
Dim wksSkill As Worksheet
MyRow = 6
Set wksSkill = Sheets("Arkusz1")
Set MyColRange = wksSkill.Range("A1:E5")
minVal = Application.WorksheetFunction.Min(MyColRange)
For Each rng In MyColRange.Columns
If Not IsError(Application.Match(minVal, rng, 0)) Then
If wksSkill.Cells(MyRow, rng.Column) = "Exclude" Then
MsgBox "Column " & rng.Column
End If
End If
Next rng
End Sub

Inserting formulas w/ FOR NEXT Loop

Couldn't find a thread that would answer my question, os here I am. Please provide a link if there is one that I have not found.
Using Excel 2010
The comments should be sufficient to show what I'm trying to do.
I'm getting the Application-defined or Object-defined error (Runtime error 1004) I just can figure it out. Any help would be appreciated. Side note: I can get the loop to work when a formula like =if(A1=B1,"",3) If actually places the formula in the cell and show 3 in each cell when the condition is met. it just adding the Column,Row, I've tried & Range($, C) &, all sorts of combinations so, show me how much of a boob I am and help me with the SIMPLE fix that eludes me.
Thanks in advance.
Private Sub CommandButton1_Click()
Dim R, C As Integer
Dim Frmla1, Frmla2, Frmla3 As String
R = 4 'Initial Row #
C = 2 'Initial Column #
Frmla1 = "=IF('Log Sheet'!" '1st half of the formula
Frmla2 = "="""","""",'Log Sheet'!" '2nd half of the formula
Frmla3 = ")" 'Closing Parenthesis
' The Cells should have incremental Column,Row Identifiers.
' The following is what I want in each cell.
' The problem is trying to get the B4 and B5 into the formula.
' Formula "=IF('Log Sheet'!B4="","",'Log Sheet'!B4)
' Formula "=IF('Log Sheet'!B5="","",'Log Sheet'!B5)
For R = 4 To 301
ActiveSheet.Cells(R, C).Value = Frmla1 & R & C & Frmla2 & R & C & Frmla3
R = R + 2
Next R
End Sub
It looks like you should be using the R and C to reference a Range.Cells property that you can return a Range.Address property from.
For R = 4 To 301 Step 2
ActiveSheet.Cells(R, C).Formula = _
Frmla1 & Cells(R, C).Address(0, 0) & Frmla2 & Cells(R, C).Address(0, 0) & Frmla3
Next R
I've also removed your R = R + 2 and changed the Step of the For ... Next to increment by 2. You shouldn't self-increment a For ... Next inside the loop.
I changed the Range.Value property assignment to Range.Formula property. While your method often works, it wasn't correct and if the cells were formatted as Text, the formulas would come into the cells as text-that-looks=like-a-formula.
Your variable declarations should be more like the following.
Dim R As Long, C As Long
Dim Frmla1 As String, Frmla2 As String, Frmla3 As String
Each declaration should carry a variable type. Without it, they are declared as object/variant types,

Excel VBA - Loop through range and set formula in each cell

I've got a workbook where I have one worksheet which contains a lot of data.
My goal is to create a macro that inserts a formula in a separate sheet to copy the data from the first sheet. Lets call the first sheet "Numbers1" and the second sheet "TidyNumbers1".
In the sheet "TidyNumbers1" I want to loop through each cell from column A to M and rows 1 to 60. So I've got a macro that so far looks like this:
Sub updateFormulasForNamedRange()
Dim row, col, fieldCount As Integer
colCount = 13
RowCount = 60
For col = 1 To colCount
For row = 1 To RowCount
Dim strColCharacter
If col > 26 Then
strColCharacter = Chr(Int((row - 1) / 26) + 64) & Chr(((row - 1) Mod 26) + 65)
Else
strColCharacter = Chr(row + 64)
End If
Worksheets("TidyNumbers1").Cells(row, col).Formula = "=IF(Numbers1!E" & col & "<>0;Numbers1!" & strColCharacter & row & ";"")"
Next row
Next col
End Sub
But the formula is supposed to looks like this for Column A, row 2:
IF(Numbers1!E2<>0;Numbers1!A2;"")"
And the formula in Column A, row 3 should look like this:
IF(Numbers1!E3<>0;Numbers1!A3;"")"
Formula in Column B, row 2 should look like this:
IF(Numbers1!E2<>0;Numbers1!B2;"")"
In other words, the formula looks to see if the value in Column E, row % is anything but 0 and copies it if conditions are met.
But, I see that I need to translate my integer variable Row with letters, because the formula probably needs "A" instead of 1. Also, I get a 1004 error (Application-defined or object-defined error) if I just try to use:
Worksheets("Numbers1").Cells(row, col).Formula = "=IF(Numbers1!E" & row & "<>0;Numbers1!" & col & row & ";"")"
I clearly see that the integer row should be translated to letters, if that's possible. Or if anyone has any other suggestions that might work. Also, the 1004 error is unclear to me why happens. I can define a string variable and set the exact same value to it, and there's no error. So it's probably the formula bar that whines about it I guess?
Here is a former post of mine containing functions for conversion of column numbers to letters and vice versa:
VBA Finding the next column based on an input value
EDIT: to your 1004 error: Try something like this:
=IF(Numbers1!E" & row & "<>0,Numbers1!A" & row & ","""")"
(use ; instead of ,, and "" for one quotation mark in a basic string, """" for two quotation marks).
Would not it be easier to get the cell address with the Cells.Address function?
For example:
MsgBox Cells(1, 5).Address
Shows "$E$1"
Best Regards

Resources