I need a code in VBA which is equivalent to match inside a vlookup in Excel.
Have got 2 sheets one MasterSheet and another required_data_sheet.
There are 18 columns in MasterSheet and in required_data_sheet there are only 11 out of 18 columns of MasterSheet (not all of these 11 columns are in same order as first 11 columns in MasterSheet). The first column in both sheets is item_id which is the primary key. MasterSheet has 45000 records and Required_data_sheet has only few hundreds rows with only 1st column (which is item ID) populated and for these few hundred other 10 (11-1st column) needs to be populated.
I can use below formula in required_data_sheet to get data from mastersheet, which gives correct result. I only write this formula in cell A2 of required_data_sheet and then copy the same in all cells.
=VLOOKUP($A2,Master,MATCH(B$1,Master[#Headers],0),FALSE)
Master is the table name of data in MasterSheet.
Problem is I am unable to write the correct VBA code for this. Code is problematic in the Match formula part.
Below is my code and Match formula is preventing it from giving the desired result.
Sub Fetch_Specific_Columns()
Dim lastrow As Long
Dim lastcolumn As Integer
Dim c As Integer
Dim r As Long
lastrow = Range("A" & Rows.Count).End(xlUp).row
lastcolumn = Range("A1").End(xlToRight).Column
For c = 2 To lastcolumn
For r = 2 To lastrow
Worksheets("Required_Data_Sheet").Cells(r, c).Formula = "=VLOOKUP(A" & r & ",Master,MATCH(" & Worksheets("Required_Data_Sheet").Cells(1, c) & ",'Master Sheet'!$A$1:$R$1,0),FALSE)"
Next r
Next c
End Sub
Expected result is somehow match formula works in the desired fashion.
The problem with your code is this portion:
MATCH(" & Worksheets("Required_Data_Sheet").Cells(1, c) & ",
It is inserting the value from cell(1,c) directly into the formula without quotes. This is incorrect excel formula syntax. Instead you should either:
Insert a cell reference (e.g. B3) or
The value of the cell in quotation marks.
Here is the whole line with the correction for method 1:
Worksheets("Required_Data_Sheet").Cells(r, c).Formula = "=VLOOKUP(A" & r & ",Master,MATCH(" & Worksheets("Required_Data_Sheet").Cells(1, c).Address & ",'Master Sheet'!$A$1:$R$1,0),FALSE)"
Here is the whole line with the correction for method 2:
Worksheets("Required_Data_Sheet").Cells(r, c).Formula = "=VLOOKUP(A" & r & ",Master,MATCH(""" & Worksheets("Required_Data_Sheet").Cells(1, c) & """,'Master Sheet'!$A$1:$R$1,0),FALSE)"
Related
I am trying to make VBA write a formula into different cells that will find the maximum value for a Range decided by some variables. My variables I and J are (numbers/Integers).
Here is my code.
Sub AddMAX()
Dim I As Integer
Dim J As Integer
Dim L As Integer
I = InputBox("Number of columns to check max value")
J = InputBox("Number of Rows to add formula inn and find max value of that row")
For L = 5 To 4 + J
Worksheets(1).Cells(L, 4 + I).Formula = "=" & Max(Range(Cells(L, 4), Cells(L, 3 + I)))
Next L
End Sub
Have tried to re-write the second part (part behind the equal sign) several times. Usually I get the message Compile error: Sub or Function not defined and it marks the "Max". I thought Max (also tried with big letters) was an in-built function like SUM and so on.
I'm trying to make it write an Excel formula like this into the cells:
For I=2 and J=3:
Cell F5: =MAX(D5:E5)
Cell F6: =MAX(D6:E6)
Cell F7: =MAX(D7:E7)
i.e. I want a formula in the cells like I had wrote it in the cells manually to calculate max value, so that if the value in Cells D5, to D7 and E5 to E7 change, the new max value will be found without any scripts having to run.
Let me know if something is unclear.
You should not be putting Range and Cells in a formula string, they mean nothing to the Excel formula engine. You need the Address of the cells:
Dim I As Long
Dim J As Long
Dim L As Long
I = InputBox("Number of columns to check max value")
J = InputBox("Number of Rows to add formula inn and find max value of that row")
L = 5
With Worksheets(1)
.Range(.Cells(L, 4 + I), .Cells(4 + J, 4 + I)).Formula = "=MAX(" & .Cells(L, 4).Address(False, False) & ":" & .Cells(L, I + 3).Address(False, False) & ")"
End With
The formula is actually the same for all cells, which is why it is possible to assign it in one assignment for the entire range. It looks different in the A1 reference notation, but if you switch to R1C1 in the Excel settings, you will see they are the same. Which also means it is easier to create that formula using the R1C1 notation in the first place:
Dim I As Long
Dim J As Long
Dim L As Long
I = InputBox("Number of columns to check max value")
J = InputBox("Number of Rows to add formula inn and find max value of that row")
L = 5
With Worksheets(1)
.Range(.Cells(L, 4 + I), .Cells(4 + J, 4 + I)).FormulaR1C1 = "=MAX(RC[-" & I & "]:RC[-1])"
End With
But it would appear to me that you should instead use the Excel interface the intended way. Select the cells in which the MAX formula should be. Keeping the entire range selected, put the MAX formula into any of its cells as if you were creating it for just that cell, but instead of pressing Enter, press Ctrl+Enter.
You have to be careful to distinct between the part that is seen by VBA and the final formula.
If you write
Worksheets(1).Cells(L, 4 + I).Formula = "=" & Max(Range(Cells(L, 4), Cells(L, 3 + I)))
Max (and all the following stuff) is seen by the VBA-interpreter, not Excel. But there is no Max-function, and you get an (compiler)-error.
If you write
Worksheets(1).Cells(L, 4 + I).Formula = "=Max(Range(Cells(L, 4), Cells(L, 3 + I)))"
the VBA-interpreter sees the whole stuff as a string. It cannot take care about variables like L or I because is doesn't see them. So you end up with a formula that is exactly like you write it - and Excel (not VBA) will show you an error because it doesn't understand L or I.
What you need is a statement (in VBA) that creates a string that contains the actual values of your variables, and assign it to the cell.formula. I strongly advice that you first assign this to a string variable - it makes debugging much easier:
Dim formula As String
formula = "=Max(Range(Cells(" & L & ", 4), Cells(" & L & ", 3 + " & I & ")))"
Debug.Print formula
Worksheets(1).Cells(L, 4 + I).Formula = formula
Update: Sorry, I haven't looked to the content of the formula at all, of course the Range and Cells-objects are VBA objects. What you need in your formula is the address of the range, so change the line to
formula = "=MAX(" & Range(Cells(L, 4), Cells(L, 3 + i)).Address & ")"
Now VBA will create a Range and put the address into the formula string.
I want a range of cells to fill in with specified information but only if column A is "GFR"
I've been able to accomplish this very simply by recording a macro, searching for GFR in Column A, then pasting in information in Columns C and G
My problem is I can't get my macro to do this for me with new data. It's go over the old data and copy in the information, but I can't replicate it, obviously.
Example data, with columns C and G already filled in with the correct information:
Test Name(O) Result(R) Units(R) Result Interpretation Flag(R) Reference Low(C) Reference High(C) Reference Alpha(C)
GFR ML/MIN/1.73M2 L >60
CREATININE
POTASSIUM
WHITE BLOOD COUNT
PLATELET COUNT
GLOBULIN
GFR ML/MIN/1.73M2 L >60
CREATININE
POTASSIUM
SGOT (AST)
I need a hint on how to start this out.
If Column A = GFR, then Column C of the same row = ML/MIN/1.73M2, and column G of the same row = >60
This should do it...
Sub FillIn()
Dim LR As Long
With ActiveSheet
LR = Cells(.Rows.Count, "A").End(xlUp).Row
For i = LR To 1 Step -1
If (.Range("A" & i).Value = "GFR") Then
.Range("C" & i).Value = "ML/MIN/1.73M2"
.Range("G" & i).Value = ">60"
End If
Next i
End With
End Sub
I am trying to create a function or functions that can sum daily hours from time cards for each client to come up with the total hours worked per day. Each client has it's own sheet inside of a single workbook.
Currently, I have a function that determines the sheet that goes with the first client (the third sheet in the workbook):
Function FirstSheet()
Application.Volatile
FirstSheet = Sheets(3).Name
End Function
And one to find the last sheet:
Function LastSheet()
Application.Volatile
LastSheet = Sheets(Sheets.Count).Name
End Function
The part that I am having trouble with it getting these to work within the sum function.
=sum(FirstSheet():LastSheet()!A1
That is basically what I want to accomplish. I think the problem is that I don't know how to concatenate it without turning it into a string and it doesn't realize that it is sheet and cell references.
Any help would be greatly appreciated.
So, an example formula would look like this:
=SUM(Sheet2!A1:A5,Sheet3!A1:A5,Sheet4!A1:A5)
That would sum Sheet2-Sheet4, A1:A5 on all sheets.
Is there a reason you need to write the VBA code to do this?
Can't you just enter it as a formula once?
Also, if you're going to the trouble of writing VBA to generate a formula, it may make more sense to just do the sum entirely in VBA code.
If not, try this:
Sub GenerateTheFormula()
Dim x, Formula
Formula = "=SUM(" 'Formula begins with =SUM(
For x = 3 To Sheets.Count
Formula = Formula & Sheets(x).Name & "!A1," 'Add SheetName and Cell and Comma
Next x
Formula = Left(Formula, Len(Formula) - 1) & ")" 'Remove trailing comma and add parenthesis
Range("B1").Formula = Formula 'Where do you want to put this formula?
End Sub
Results:
The functions return strings and not actual worksheets. The Worksheet does not parse strings well. So add a third function that uses the Evaluate function:
Function MySum(rng As Range)
MySum = Application.Caller.Parent.Evaluate("SUM(" & FirstSheet & ":" & LastSheet & "!" & rng.Address & ")")
End Function
Then you would simply call it: MySum(A1)
It uses the other two function you already have created to create a string that can be evaluated as a formula.
I didn't understand ur question completely but As I understood u have different sheets of different clients which contains supoose column 1 date and column 2
contains hours on that particular date wise hours and a final sheet which column1 contains name of client and column 2 contains total hoursPlease try it
Sub countHours()
Dim last_Row As Integer
Dim sum As Double
sum = 0
'Because I know number of client
For i = 1 To 2 'i shows client particular sheet
last_Row = Range("A" & Rows.Count).End(xlUp).Row
Sheets(i).Activate
For j = 2 To last_Row
'In my Excel sheet column 1 contains dates and column 2 contains number of hours
sum = sum + Cells(j, 2)
'MsgBox sum
Next j
'Sheet 3 is my final sheet
ThisWorkbook.Sheets(3).Cells(i + 1, 2).Value = sum
sum = 0
Next i
End Sub
Happy Coding :
I have a data set in which there is an id field and a number of other fields.
The id field at times has a second id. In this case, I need to create a new duplicated record and put a single id in each of the records. There is an additional condition in which each of the ids may be followed by a number which is a percentage. In all cases, I need to display the correct percentage as a decimal value in a field on the record.
id examples:
AJ01-25/ST01-75
AJ01/LM03
RICH01
Correct representation of ids and percentages:
id percent
AJ01 .25
ST01 .75
AJ01 .5
LM03 .5
RICH01 1.0
I used the following code to create a new record and parse any percentages into a new field whenever a "/" is detected, but I'd very much like to have something cleaner. Sort order does not matter (my script places new records at the end). Thoughts?
Sub breakemup()
Dim wb As Workbook
Dim ws As Worksheet
Dim id As String
Dim rng As Range
Dim ar() As String
Set wb = ThisWorkbook
Set ws = wb.Worksheets("data")
Dim currentRow As Integer
Dim finalRow As Integer
finalRow = ws.UsedRange.Rows.Count
For currentRow = 2 To finalRow
ar() = Split(ws.Range("a" & currentRow).Value, "/")
If UBound(ar) = 1 Then
ws.Rows(currentRow).Copy Destination:=ws.Range("A" & Rows.Count).End(xlUp).Offset(1)
If UBound(Split(ar(1), "-")) = 1 Then
ws.Range("A" & Rows.Count).End(xlUp).Value = Split(ar(1), "-")(0)
ws.Range("A" & Rows.Count).End(xlUp).Offset(0, 1).Value = CDbl(Split(ar(1), "-")(1)) / 100#
ws.Range("A" & currentRow).Value = Split(ar(0), "-")(0)
ws.Range("A" & currentRow).Offset(0, 1).Value = CDbl(Split(ar(0), "-")(1)) / 100#
Else
ws.Range("A" & Rows.Count).End(xlUp).Value = ar(1)
ws.Range("A" & Rows.Count).End(xlUp).Offset(0, 1).Value = 50 / 100#
ws.Range("A" & currentRow).Value = ar(0)
ws.Range("A" & currentRow).Offset(0, 1).Value = 50 / 100#
End If
Else
ws.Range("A" & currentRow).Offset(0, 1).Value = 1#
End If
Next
End Sub
Not sure if you would consider this cleaner but here is a formula solution rather than a VBA one. It uses the functions:
INDIRECT
MID
LEN
IF
RIGHT
FIND
Lets say we have the following in sheet 1:
Insert the following formulas in sheet 2:
Cell A2:
=IF(E2=1, IF(D2="", IF(C2="", INDIRECT(G2), LEFT(INDIRECT(G2), C2-1)), LEFT(INDIRECT(G2), D2-1)), IF(D2="",IF(C1="", INDIRECT(G2), RIGHT(INDIRECT(G2), LEN(INDIRECT(G2))-C1)), MID(INDIRECT(G2), C1+1, D2 -1-C1)))
Drag / Copy it down to cover the rest of the cells in column A
Cell B2:
=IF(E2=1,IF(C2="",IF(D2="",1,MID(INDIRECT(G2),C2+1,LEN(INDIRECT(G2)))),IF(D2="",0.5,MID(INDIRECT(G2),D2+1,C2-D2-1)/100)), IF(D2="",0.5,MID(INDIRECT(G2),D2+1, LEN(INDIRECT(G2))-D2)/100))
Drag / Copy it down to cover the rest of the cells in column B
Cell C2:
=IF(E2=1, IF(ISNUMBER(FIND("/",INDIRECT(G2))),FIND("/", INDIRECT(G2)), ""), "")
Drag / Copy it down to cover the rest of the cells in column C
Cell D2:
=IF(E2=1, IF(ISNUMBER(FIND("-", INDIRECT(G2))),FIND("-", INDIRECT(G2)), ""),IF(D1 ="", "", FIND("-", INDIRECT(G2), D1+1)))
Drag / Copy it down to cover the rest of the cells in column D
Cell E2:
The number value "1"
Cell E3:
=IF(E2=1, IF(C2="", 1, 2),1)
Drag / Copy it down to cover the rest of the cells in column E
Cell F2:
the number value "1"
Cell F3:
=IF(E3=1, F2+1, F2)
Drag / Copy it down to cover the rest of the cells in column F
Cell G2:
="Sheet1!A" & TEXT(F2, 0)
Drag / Copy it down to cover the rest of the cells in column G
Result:
You could hide the extra columns so you only see the columns you need:
I have an article on my blog that provides an example with pretty much the same functions used here, it might help with understanding the functions used Excel Functions and Formulas Sample #1, Split Strings Based on Delimeter
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