I am using the below code to look up data in another workbook and collect the data. I have been able to get it to work in book 2.xlsm for my data entry sheet that is located in test.xlsx
Sub copydata()
Dim rw As Long, x As Range
Dim extwbk As Workbook, twb As Workbook
Set twb = ThisWorkbook
Set extwbk = Workbooks.Open("/Users/username/desktop/test.xlsx")
Set x = extwbk.Worksheets("Data entry").Range("A1:GZ400")
With twb.Sheets("Sheet1")
For rw = 4 To .Cells(Rows.Count, 1).End(xlUp).Row
.Cells(rw, 2) = Application.VLookup(.Cells(rw, 1).Value2, x, 11, False)
Next rw
End With
With twb.Sheets("sheet1")
For rw = 4 To .Cells(Rows.Count, 1).End(xlUp).Row
.Cells(rw, 3) = Application.VLookup(.Cells(rw, 1).Value2, x, 12, False)
Next rw
End With
extwbk.Close savechanges:=False
End Sub
What I want to be able to do is also get VBA to pull (I'm guessing using a combo of indirect and vlookup?) the integral data from the additional sheets in test.xlsx and place in book2 integral values. These sheet names in test.xlsx will change based on the sample name, but those names will be the same names that are in sheet1 of book2, same for the integral names.
Can someone help guide me to how I can add on to this code and address this? I am new to VBA so I am still learning. My actual documents are much larger and so I will need to tweak the reference cells in the end so please try to explain what some of the things mean so I know what I will be doing.
Note: working code at the end.
I'd say that the easiest way to act is to write a working formula for the range you want to fill. You can then start to record a macro of you typing the formula. With some edit, you can properly insert the resulting code in your subroutine.
STEP 1: writing the formula.
Since in your subroutine the test.xlsx will be open, your formula can be written and tested while test.xlsx is opened. You already have rightfully guessed the formula you need (VLOOKUP and INDIRECT). But for the sake of explanation, let's assume you've started with a simplier formula, like this one for the cell D4:
=VLOOKUP(D$3,'[test.xlsx]sample 1'!$D:$H,5,FALSE)
To make it dynamically choose the right sheet, we need to edit the table_array part. Within it, two parts are constant: '[test.xlsx] and '!$D:$H. They can be written as strings. The sample 1 is contained in the first cell of the row, so we will just write a reference to it. Our formula will therefore look like this:
=VLOOKUP(D$3,INDIRECT("'[test.xlsx]" & $A4 & "'!$D:$H"),5,FALSE)
Our formula is fairly functional. Let's record the macro.
STEP 2: recording and editing the macro.
Start the recording, select the cell with the formula, press F2, press enter, stop the recording. You can then go to VBA and there you'll find (presumably in a new module) the macro you've just recorded. It will most likely look like this:
Sub Macro1()
'
' Macro1 Macro
'
'
Range("D4").Select
ActiveCell.FormulaR1C1 = _
"=VLOOKUP(R3C,INDIRECT(""'[test.xlsx]"" & RC1 & ""'!$D:$H""),5,FALSE)"
Range("D5").Select
End Sub
Of all this code, what we really care about is the .FormulaR1C1 = "=VLOOKUP(R3C,INDIRECT(""'[test.xlsx]"" & RC1 & ""'!$D:$H""),5,FALSE)". As you can see, it changes the property FormulaR1C1 of the given range. Basically we can insert a string that (if correctly formatted) it will be read as a formula with RC (row-column) type references. More information about it here. While integrating this formula, we can also change the '[test.xlsx] part to use a reference depending on our code. Thefore we change this:
.FormulaR1C1 = "=VLOOKUP(R3C,INDIRECT(""'[test.xlsx]"" & RC1 & ""'!$D:$H""),5,FALSE)""
into this:
.FormulaR1C1 = "=VLOOKUP(R3C,INDIRECT(""'[" & extwbk.Name & "]"" & RC1 & ""'!$D:$H""),5,FALSE)"
This way in case extwbk had a different name, the resulting formula would still work. We could also do the same thing basically with all the variables in the formula.
Now we need to determine the formula's range of destination. We already have a range variable in our code that we can use. Mind that a single letter name for a variable is not the best. You should choose a name with at least 3 letters that you presumably won't find in the rest of the code. This will make easier the search and eventually the edit of the given variable. It's also a good practice to add a "tag" to the variable to underline what kind of variable it is (example Rng if it's a range, like RngMyCell). It can be also risky to use the same vaguely called variable for different purpouse in a code, but since it's a really short code we should be fine (and you can still improve the code accordingly later). Anyway, to determine the range we can use Resize and Offset starting from the cell D3 like this:
With twb.Sheets("Sheet1")
Set x = .Range(.Range("D3"), .Cells(3, .Columns.Count).End(xlToLeft))
Set x = x.Resize(.Cells(.Rows.Count, 1).End(xlUp).Row - 3, x.Columns.Count).Offset(1, 0)
End With
We can then apply our formula to the x range. Since we are interested in the formulas' results and not in the formulas themselves we can add a x.Values = x.Values line to sobstitute the formulas with their results. Our code will therefore be like this:
With twb.Sheets("Sheet1")
Set x = .Range(.Range("D3"), .Cells(3, .Columns.Count).End(xlToLeft))
Set x = x.Resize(.Cells(.Rows.Count, 1).End(xlUp).Row - 3, x.Columns.Count).Offset(1, 0)
x.FormulaR1C1 = "=VLOOKUP(R3C,INDIRECT(""'[" & extwbk.Name & "]"" & RC1 & ""'!$D:$H""),5,FALSE)"
x.Value = x.Value
End With
Our code is ready to be integrated into our subroutine.
STEP 3: integrating the code
We can place our code in our subroutine. But first we can also merge the two With twb.Sheets("Sheet1") since they are identical and put our code within the same with statement. We can also note that in our For-Next cycles a point is missing. The end result of should be like this:
Sub copydata()
Dim rw As Long, x As Range
Dim extwbk As Workbook, twb As Workbook
Set twb = ThisWorkbook
Set extwbk = Workbooks.Open("/Users/username/desktop/test.xlsx")
Set x = extwbk.Worksheets("Data entry").Range("A1:GZ400")
With twb.Sheets("Sheet1") '<-- this with is the same as the next one. No need to repeat it.
For rw = 4 To .Cells(.Rows.Count, 1).End(xlUp).Row '<-- the ".Rows.Count" didn't have the point.
.Cells(rw, 2) = Application.VLookup(.Cells(rw, 1).Value2, x, 11, False)
Next rw
For rw = 4 To .Cells(.Rows.Count, 1).End(xlUp).Row '<-- the ".Rows.Count" didn't have the point.
.Cells(rw, 3) = Application.VLookup(.Cells(rw, 1).Value2, x, 12, False)
Next rw
Set x = .Range(.Range("D3"), .Cells(3, .Columns.Count).End(xlToLeft))
Set x = x.Resize(.Cells(.Rows.Count, 1).End(xlUp).Row - 3, x.Columns.Count).Offset(1, 0)
x.FormulaR1C1 = "=VLOOKUP(R3C,INDIRECT(""'[" & extwbk.Name & "]"" & RC1 & ""'!$D:$H""),5,FALSE)"
x.Value = x.Value
End With
extwbk.Close savechanges:=False
End Sub
Related
Hi i want to show an output to a specific cell at B column but i really don't have any idea on how to make it to show. Example: if "A2" has the record i want "B2" to show the output. If "A100" has the record, i want "B100" to show the output
Sub Testing()
Dim cell As Range
For Each cell In Range("A2:A4")
If cell.Value = "yes.com" Then
Range("B2:B4").Value = "Correct"
End If
Next
End Sub
The code above shows the output data "Correct" from "B2" to "B4" but what i want it to show on only the specific cell. Please Help
Currently you are looping through a range object. Per cell. One a small dataset this is fine but in your current attempt you'll need to change:
Range("B2:B4").Value = "Correct" for cell.Offset(0,1).value = "Correct"
As per my comment, you can do this a bit smarter/faster. Looping through worksheet cells is slow, certainly on large datasets (a 1000 rows is not that many yet to be honest). Nonetheless it's good to know that a good practice is to go through arrays. Let me show you below:
Sub Testing()
Dim lr As Long, x As Long
Dim arr As Variant
With Sheet1 'Change accordingly
lr = .Cells(.Rows.Count, 1).End(xlUp).Row
arr = .Range("A2:B" & lr)
For x = LBound(arr) To UBound(arr)
If arr(x, 1) = "yes.com" Then
arr(x, 2) = "correct"
End If
Next x
.Range("A2:B" & lr).Value = arr
End With
End Sub
So you can see a few things that will be helpfull:
A reference to a sheet (through a CodeName to refer to a range's parent. Without it, the macro will simply reference the ActiveSheet which is for obvious reasons not always the correct one.
I have made use of a dynamic sized array. The lr variable will get the last used row in column A, so you don't have to work through full qualified references no more.
The arr variable is an array which takes the values from the specified range into memory. Running through data in memory is much quicker than a loop/iteration over worksheet cells. This will become much more noticable when you would have even larger datasets.
I wrote the array back to the range in one go instead of several writings.
Hopefully that helped =)
As previously mentioned a 1000 rows is still not that much. Allthough I suggest you stick with the Array approach, you can also Evaluate column A and fill column B accordingly in one go instead of stepping through a range object. It's an array formula in disguise so not very quick on actual large datasets.
Sub Testing()
Dim lr As Long
Dim rng As Range
With Sheet1 'Change accordingly
lr = .Cells(.Rows.Count, 1).End(xlUp).Row
Set rng = .Range("A2:B" & lr)
rng.Columns(2).Value = .Evaluate("IF(" & rng.Columns(1).Address & "=""yes.com"",""correct"","""")")
End With
End Sub
Just try:
Sub test()
Dim i As Long
For i = 1 To Rows.Count
If Cells(i, 1) = "yes.com" Then Cells(i, 2) = "Correct"
Next
End Sub
It will loop through entire A column.
Alternatively, you can enter in B1 formula:
=IF(A1="yes.com","Correct","")
and drag it all the way down.
I'm trying to grab the values from a different worksheet and match them to the their sister data in my main sheet in column A but I'm having issues with getting the right results, I was thinking of going the Vlookup route but I can't quite get it to work properly. I found a funky way of getting it done but I'm trying to save just the values and not the formula itself.
This is what I tried at first
Sub matchID()
'Dim wb As Workbook
'Set wb = ActiveWorkbook
'
'With wb.Sheets("Data")
' .Range("E2:E" & .Range("A" & .Rows.Count).End(xlUp).Row).Formula = "=VLOOKUP(A2,ID!A:B,2,FALSE)"
'End With
'the above works but need to save values and not formula
It kinda works but I need that values and not the formula, my plan is to find the data I need and then save a copy of the file as a csv
I tried using a different method but I'm running into runtime error '1004'
I'm still learning VBA so I feel like I'm spinning my wheels right now.
Can someone show me what I'm doing wrong?
Sub matchID()
'this is what I'm trying to get to work but unsure if I will still end up with formula and not just values
Dim result As String
Dim sheet As Worksheet
Dim lrow As Integer
Dim i As Integer
Set sheet = ActiveWorkbook.Sheets("Data")
lrow = sheet.UsedRange.Rows(sheet.UsedRange.Rows.Count).Row
For i = 2 To lrow
result = Application.WorksheetFunction.VLookup("A2", Sheets("ID").Range("A:B"), 2, False)
Cells(i, 5).Value = result
Next
End Sub
I'm trying to lookup all IDs(in column B) from my second sheet("ID") using the values in column A from my primary sheet("Data") and then populate the all results in column E in my primary sheet to their match.
My first try kinda worked but instead of leaving just the value it leaves the formula in the cell e.g. =VLOOKUP(A2,ID!A:B,2,FALSE) when really I'm looking for just the value 8447 that it shows before clicking on the cell.
If you want to get rid of the formula, just paste as values:
Sub matchID()
Dim wb As Workbook
Set wb = ActiveWorkbook
With wb.Sheets("Data")
.Range("E2:E" & .Range("A" & .Rows.Count).End(xlUp).Row).Formula = "=VLOOKUP(A2,ID!A:B,2,FALSE)"
.Range("E2:E" & .Range("A" & .Rows.Count).End(xlUp).Row).Value = .Range("E2:E" & .Range("A" & .Rows.Count).End(xlUp).Row).Value
End With
End Sub
I'm trying to program a VLookup Table in VBA that references another file. Here is a simple outline of my goal:
Look up value in cell A2 in another Excel file
Pull the information in from column 2 of the other Excel file and place in Cell B2
Move on to cell A3 and repeat the process until there are no more entries left in column A
Here is the code that I already have. I keep getting an error that says "Unable to get the VLookup property of the WOrksheetFunction class." I checked the other posts referencing that error but they were not of any help. Do you all see an error in my code? Or does anyone have a better way of accomplishing this task?
Sub SBEPlannerAdder()
Dim wbk As Workbook
Set wbk = Workbooks.Open("C:\Users\user\Documents\Support File\Planner.xlsx")
With Sheets("Sheet1")
' Selects the first cell to check
Range("A2").Select
Dim x As Variant
x = wbk.Worksheets("Sheet1").Range("A1:C1752")
' Loops through all rows until an empty row is found
Do Until IsEmpty(ActiveCell)
Range(ActiveCell.Offset(0, 1) & ActiveCell.Row).Value = Application.WorksheetFunction.VLookup((ActiveCell.Column & ActiveCell.Row), x, 2, 0)
ActiveCell.Offset(1, 0).Select
Loop
End With
Call wbk.Close(False)
End Sub
When you open a workbook, it becomes the active workbook. It seems you were never passing control back to the target workbook.
Sub SBEPlannerAdder()
Dim rw As Long, x As Range
Dim extwbk As Workbook, twb As Workbook
Set twb = ThisWorkbook
Set extwbk = Workbooks.Open("C:\Users\user\Documents\Support File\Planner.xlsx")
Set x = extwbk.Worksheets("Sheet1").Range("A1:C1752")
With twb.Sheets("Sheet1")
For rw = 2 To .Cells(Rows.Count, 1).End(xlUp).Row
.Cells(rw, 2) = Application.VLookup(.Cells(rw, 1).Value2, x, 2, False)
Next rw
End With
extwbk.Close savechanges:=False
End Sub
See How to avoid using Select in Excel VBA macros for more methods on getting away from relying on select and activate to accomplish your goals.
It depends on whether you plan to do this as a one off or repeatedly. I'm assuming repeatedly since doing this manually is not all that difficult.
The first thing I would look at is your arguments. The first two should be ranges. So to be clear, perhaps you could do something like
Dim x As Range
set x = wbk.Worksheets("Sheet1").Range("A1:C1752")
...
Range(ActiveCell.Offset(0, 1) & ActiveCell.Row).Value = Application.WorksheetFunction.VLookup(Range(Activecell.Address), x, 2, 0)
The important bits are making sure your first two arguments are Ranges for the Vlookup function.
In Excel 2013, having sheet named "Tags", I am trying to set a printing area from A2 till end of page, ending with column L.
Worksheets("Tags").PageSetup.PrintArea = Worksheets("Tags").Range( _
Cells(2, 1), Cells(Worksheets("Tags").Range("A65536").End(xlUp).Row, 12))
My code compiles okay, but it does not seems to work - no printing area has been set.
What should be a correct macro to set printing area?
It's easier to see what is happening if you declare a few variables and decompose your statement.
Try this:
Sub SetPrintArea()
Dim ws As Worksheet
Dim lastRow As Long
Set ws = ThisWorkbook.Sheets("Tags")
' find the last row with formatting, to be included in print range
lastRow = ws.UsedRange.SpecialCells(xlCellTypeLastCell).Row
ws.PageSetup.PrintArea = ws.Range("A2:L" & lastRow).Address
End Sub
Alternatively, if you want to find the lastRow with data, you can find the lastrow like this:
lastRow = ws.Cells.Find("*", SearchOrder:=xlByRows, SearchDirection:=xlPrevious).Row
Note that the 65536 value you're using as the starting point to find the last row is obsolete (although it will frequently still work) as of Excel 2007, which has over a million rows per sheet.
A few things to note about your approach:
Cells(2,1) is A2. The syntax is Cells([row], [column])
You want the last populated row in column L, but are looking in column A instead. Range("A65536").End(xlUp).Row
This results in a print area (once you've added the .Address to your range) of A1:L2. Why A1? Because the column A is empty, and the lastrow is therefore row 1. You have set the range to be A2:L1, which becomes A1:L2.
You need to add .Address at the end of your code.
Worksheets("Tags").PageSetup.PrintArea = Worksheets("Tags").Range( _
Cells(2, 1), Cells(Worksheets("Tags").Range("A65536").End(xlUp).Row, 12)).Address
PageSetup.PrintArea Property
Returns or sets the range to be printed, as a string using A1-style references in the language of the macro. Read/write String.
I'm new to vba programming and I would like to work on a function to fix salutations in an excel file.
To start, I would just like to append a Dear " to a name in the first column, and put this value in the next column, so that I would end up with the name in the first column and "Dear name" in the next column.
The function I have so far, is putting "Dear " in the next column, but it is not appending that to the text in the first column. Could someone help me correct my code?
Sub letterSalutationFixer()
Dim letterSalutationColumn As Range
Set letterSalutationColumn = Columns(1)
For Each Cell In letterSalutationColumn
Cell.Offset(, 1).Value = "Dear " & Cell.Text
Next
End Sub
PS. I do realise that I don't necessarily need to do this programmatically since it doesn't take that long to do with the functions already available, but I eventually want to expand this to fix other data with more complexity - and just thought I could start with something simple.
Many thanks in advance!
The reason it's blank is that Cell is equivalent to the whole column. You're close though. If you did...
For Each Cell In letterSalutationColumn.Cells
..l it would cycle through each cell.
However, the way it's written, it would cycle through each cell in the whole column, which could crash Excel, or at least slow things way down.
Here's a reworked version of what you're trying to do. It only acts on the cells in column A with content:
Sub Salutation()
Dim ws As Excel.Worksheet
Dim LastRow As Long
Dim NameRange As Excel.Range
Dim cell As Excel.Range
Set ws = ActiveSheet
With ws
LastRow = .Range("A" & .Rows.Count).End(xlUp).Row
Set NameRange = .Range("A2:A" & LastRow)
For Each cell In NameRange
cell.Offset(, 1) = "Dear " & cell.Text
Next cell
End With
End Sub
It also declares all variables, something you want to get in the habit of doing. Do a search on Option Explicit to learn how to force yourself to.
It also uses a With statement to fully qualify Object references, so that instead of just referring to Column(1) or Range(something) you're specifying that it's in ws, which has been set to the ActiveSheet.
Another way is the VBA alternative of
Using a formula in column B that runs the concatenation against the used part of column A (ie in B1 ="Dear " &A1 etc)
The formula then is copied over itself as a value to remove the formula
code
Sub QuickCon()
Dim rng1 As Range
Set rng1 = Range([a1], Cells(Rows.Count, "A").End(xlUp))
With rng1.Offset(0, 1)
.FormulaR1C1 = "=""Dear "" &RC[-1]"
.Value = .Value
End With
End Sub