VBA Excel - Extend Formulas Down (Complicated) - excel

Scenario:
I have a consistent formula starting in Range("V4").
This range has a Defined Name: Stock4 (This is so the formula/cell can be relatively referenced if the user adds or removes surrounding columns).
The spreadsheet is constantly updated with fresh data (Pasted in Range("A4:U4")).
The amount of pasted rows varies with each batch of data.
I need to extend the formula within Stock4 down to the last row...
What I'm doing:
So, I'm using a combination of...
Dim Lastrow As Integer
Lastrow = ActiveSheet.Cells(Rows.Count, 1).End(xlUp).Row
And
.AutoFill Destination:=Range(*insert range here*), Type:=xlFillDefault
And my cell's Defined Name: Stock4.
Here is what I get:
Range("Stock4").AutoFill Destination:=Range("Stock4:$V" & Lastrow), Type:=xlFillDefault
This works very well, however...
$V
...is not relative.
My attempted solutions:
I have tried using Split(ActiveCell.Address(1, 0), "$")(0) & Lastrow
This returns the ActiveCell Column Letter: V and Lastrow Row Number: 4831.
However...
I can't simply substitute this code into my existing code in place of $V" & Lastrow (see below)
Range("Stock4").AutoFill Destination:=Range("Stock4:Split(ActiveCell.Address(1, 0), "$")(0) & Lastrow"), Type:=xlFillDefault
Syntax errors aside, this simply won't work.
Question:
How can I extend the formula located in Stock4 down to the last row of Stock4's column (relative reference) using VBA code.
(This code is then going to be adapted and repeated for multiple relative columns across multiple spreadsheets)
To sum up:
Extend Formulas Down To Lastrow Using Defined Name Ranges And Relative Columns.
(I have spent the best part of 2 working days going grey with this problem - Is it possible? It must be possible!)

You could pass it to a variable and use this notation:
Sub MrJ()
Dim rng As Range
Dim lastrow As Integer
lastrow = ActiveSheet.Cells(Rows.Count, 1).End(xlUp).Row
Set rng = Range("Stock4")
rng.AutoFill Destination:=Range(rng.Address, Cells(lastrow, rng.Column))
End Sub

Related

Countif with reference to different sheet

Hello I will need help with problem I am facing right now and even Google couldn't help me.
I would like to add to field AS2 a COUNTIF formula with source information from different sheet.
This COUNTIF should jump to sheet ee_lpk and then take a range from column A2 down to the end of last used row. and compare that with criteria from field D.
so for AS2 will be comparing with D2 for AS3 with D3.
When I recorded that it showed:
ActiveCell.FormulaR1C1 = COUNTIF(ee_lkp!R[-143]C[-44]:R[217]C[-44],R[-143]C[-41])"
this is working but just in case that there is on ee_lpk page same number or rows what is changing from day to day.
Any help will be much appreciated.
Martin
You need to break this problem down using variables. Try something like this:
sub Answer()
Dim srcRng as Range
Dim srcLength as Long
'First find how many rows on sheet ee_lpk and store it as a variable
srcLength = Sheets("ee_lkp").UsedRange.Rows.Count
'Then use that variable to get your range
Set srcRng = Range(Cells(2,1), Cells(srcLength, 1))
'Or another viable option would be:
'Set srcRng = Range("A2:A" & srcLength)
'Then put that in your Countif formula
ActiveCell.FormulaR1C1 = _
"=COUNTIF(ee_lkp!" & srcRng.Address(True, True, xlR1C1) & ", R[-143]C[-41])
End Sub

Replicating values

Need a little help here.
In the "Data" Tab I want to copy values in column "c2:c1000" and paste in column "a1" of another Tab.
This is what i have so far,
Dim x As Long
Dim lastRow As Long
lastRow = Worksheet("Data").Cells(3, Columns.Count).End(xlUp).Column
For x = 1 To lastRow
If Worksheets("Sheet2").Cells(2, "A") = "" Then
Worksheets("Data").Range("c2:c1000").Copy Destination:=Worksheets("Sheet2").Range(1, "A")
Sheets("Sheet2").Range("A1").Value = Format(Now, "mm/dd/yyyy HH:mm:ss")
Else
Worksheets("Data").Range("c2:c1000").Copy Destination:=Worksheets("Sheet2").Cells(2,
Columns.Count).End(xlToLeft).Offset(, 1)
'Sheets("Sheet2").Range("A1").Value = Format(Now, "mm/dd/yyyy HH:mm:ss") --> can't figure how to increment this as this will need to be on the subsequent empty column
End If
Next
End Sub
Your help will be greatly appreciated!
Thank you.
Pasting values first into range A1 and down and then next time to cell B1 and so on, leaves no space for the timestamp to A1, B1 etc. So, I assume that you would like to paste the random values to row 2. So cells A1, B1, ... are left for the timestamp.
Inside the With statements we can refer to properties of the wsAudit so we can replace the "Worksheets("Audit")." reference with just "."
The column.count expression just checks the amount of columns in the worksheet.
The expression .Cells(2, Columns.Count) just points to last cell in the row 2.
The .End(xlToLeft).Column then looks from this column to left and is supposed to find the last not empty cell on this row. It's basically the same idea that in Excel's sheet you would go to cell XDF2 and hit CTRL+Arrow Left from keyboard.
But instead of activating the cell we just want to get the columns index number and then add 1 (the new column) and save it into variable. Now the new column is known.
The expression Range(.Cells(2, newColAudit), .Cells(1000, newColAudit)).Value is really the same as e.g. Range("B2:B1000"), but with this we can use the row and column index numbers instead. This is useful as the column number varies.
And as Samuel pointed out the copy paste operation can be avoided by setting the areas equal.
Dim wsAudit As Worksheet
Dim newColAudit As Long
Set wsAudit = Worksheets("Audit")
With wsAudit
newColAudit = .Cells(2, Columns.Count).End(xlToLeft).Column + 1
Range(.Cells(2, newColAudit), .Cells(1000, newColAudit)).Value = Worksheets("Data").Range("C2:C1000").Value
.Cells(1, newColAudit).Value = Format(Now, "mm/dd/yyyy HH:mm:ss")
End With
Much like your LastRow* variable for your source sheet, create a LastColumn variable for your destination sheet, which will find the last used column the same way you are finding your last used row.
Like so:
Dim LastColumn As Long
LastColumn = Sheets("Audit").Cells(1, Columns.Count).End(xlToLeft).Column
Then use the variable like so:
Destination:= Worksheets("Audit").Cells(1, LastColumn)
It seems that your code contradicts your question too, in your question you explained the data will be written to the Audit sheet in row 1, using the next column each time but your code looks for values in row 2 in your If statement:
If Worksheets("Audit").Cells(2, "A") = "" Then is the same as If Worksheets("Audit").Range("A2") = "" Then.
If you mean to check the first row, change the 2 to 1.
To help improve your codes efficiency:
(Also see the link to 'how to avoid select' in that question):
You can achieve 'copy/paste' without actually using the 'copy' and 'paste' methods by assigning the value of one range to the other, as example, like so:
Worksheets("Audit").Cells(1, LastColumn).Resize(999, 1) = Worksheets("Data").Range("c2:c1000").Value
Note: Change the Resize Property rows to suit the source range (in this case you are wanting to move values from C2:C1000).
*The LastRow variable is a bit confusing, as it is looking for the last used column in row 3.
If it's meant to find a column, consider renaming it to avoid confusion later on in debugging.
If it's meant to find the last row, try like this:
LastRow = Worksheet("Data").Cells(Rows.Count, 1).End(xlUp).Row

Autofill Dynamic Column

Trying to Autofill Column X and Column Y with text
Where Column Z determines the table length
Starting cell for column Z is "Z3" but column "X and Y" are dynamic
Last filled cell in column "X & Y" carries the text required.
Current Last cells is "X56" and "Y56"
Current last cell in column Z is "Z89"
I can easily get to x56 or y56 using
Range("Y3").Select
Selection.End(xlDown).Select
Selection.AutoFill Destination:=Range("Y56:Y89")
Range("Y56:Y89").Select
Range("X56").Select
Selection.AutoFill Destination:=Range("X56:X89")
Range("X56:X89").Select
However the solution eludes me to remove absolute references due to the dynamic nature of the information being imported and added to the column of previous information.
I tried this code i read through my research but couldn't make it work
lastRow = Range("Y3").End(xlDown).Row
Selection.AutoFill Destination:=Range("Y3:Y" & lastRow), Type:=xlFillDefault
Any assistance would be really appreciated as this appears to be the lynch pin to completing this task
Cheers
Mick
with I am trying to stack reports generated on a 12 hourly basis.
into an accrued 24 data table. This will then be accrued into a monthly data table.
As base information is downloaded in csv format. The four reports are formatted differently so i also have to stack the four reports in two table separated and itemised by date and shift.
This then allows the use of lookups, countifs sumifs etc to populate my outputs.
The four reports are dynamic and open to the potential of having a number of blank cells throughout.
I have written code that is robust enough to achieve this short of this one issue.
As the four reports do not have time stamps i am forced to use file names (column A:A) to populate the Date and Shift ranges (column A:B) as well as (Column X:Y) but need to drag the text down to cover all rows of information
Range("Y3").Select
Selection.End(xlDown).Select
Selection.AutoFill Destination:=Range("Y56:Y89")
Range("Y56:Y89").Select
Range("X56").Select
Selection.AutoFill Destination:=Range("X56:X89")
Range("X56:X89").Select
Autofill Columns with text without absolute references to allow for dynamic column range and without known starting point on the column
Do not use xlDown to find the last row. You may want to have a look at this Finding Last Row
Is this what you are trying? I have given you two option. Take your pick.
Option Explicit
Sub SampleA()
Dim ws As Worksheet
Dim lRow As Long
'~~> Change this to the relevant sheet
Set ws = Sheet1
With ws
'~~> Get last row in Col Z
lRow = .Range("Z" & .Rows.Count).End(xlUp).Row
'~~> Autofill formula in 1 go
.Range("X3:X" & lRow).Formula = .Range("X3").Formula
.Range("Y3:Y" & lRow).Formula = .Range("Y3").Formula
End With
End Sub
Sub SampleB()
Dim ws As Worksheet
Dim lRow As Long
Dim rng As Range
'~~> Change this to the relevant sheet
Set ws = Sheet1
With ws
'~~> Get last row in Col Z
lRow = .Range("Z" & .Rows.Count).End(xlUp).Row
Set rng = .Range("X3:Y3")
rng.AutoFill Destination:=.Range("X3:Y" & lRow)
End With
End Sub

VBA Sumif vs Sumifs

UPDATE:
Thank you for your help thus far! That definitely worked.
I am wondering though if there is a way to add a loop function as well. What i would like it to do is to reference Column A of Worksheet 888 to identify the same value in Column A of 999, and sum the values in the last column of the sheet (keeping in mind that the last column may differ, thus allowing the macro to be more dynamic).
Dim LastRow, LastColumn As Long
LastRow = Cells(Rows.Count, "A").End(xlUp).Row
LastColumn = Worksheets("888").Cells(1,
Columns.Count).End(xlToLeft).Column
For x= 1 To LastRow
Cells(x, 2).Value =
WorksheetFunction.SumIf(Worksheets("888").Range("A:LastRow"),
Worksheets("999").Range("A:LastRow"),
Worksheets("888").Range("LastColumn:LastColumn"))
Next c
I keep getting the error "Unable to get the SumIf property of the worksheet function class. Any thoughts on how to fix?
i don't really understand why do you want to use macro when formula can do the job
put below in C2 and drag down the formula should do the job
=SUMIF(Sheet2!F:F,A2,Sheet2!H:H)+SUMIF(Sheet3!J:J,A2,Sheet3!L:L)
but if you insist macro,
Worksheets("Sheet1").Range("C2").Value = "=SUMIF(Sheet2!F:F,A2,Sheet2!H:H)+SUMIF(Sheet3!J:J,A2,Sheet3!L:L)"
Worksheets("Sheet1").Range("C2:C7").FillDown

Inserting a formula all the way to the last row in the last empty column

I am fairly new to writing macros in VBA, but I am doing my best to learn as much as I can as quickly as possible. Anyway, the task I am trying to perform is pretty simple, but I'm having trouble coming up with a way to do it.
What I want to do is paste a formula into all of the rows in the last empty column of a spreadsheet.
So in this case, into the highlighted cells shown in the screenshot:
Example:
However, I don't want to rely on typing ("K1:K" & lastrow), what I want to do is create reference to the last column and the last row.
So far I've only been able to paste the formula into the entire column by using this:
lastcol = .Cells(1, .Columns.Count).End(xlToLeft).Offset(0, 1).Column
fvlookup = "=vlookup(#1,#2,#3,False)"
fvlookup = Replace (fvlookup, "#1", rng.Address)
fvlookup = Replace (fvlookup, "#2", [LookupFile.csv]LookupFile!$B:$1")
fvlookup = Replace (fvlookup, "#3", "5")
.Columns(lastcol).Formula = fvlookup
But later on in the process I'm working on, I want to remove all of "#N/A" and place them into a different tab named "JEs" because some of the items in the table actually don't have a value in the table I'm looking up to, and need JEs created for them. So, I would have a lot of unnecessary rows in the new tab if I went down this route.
Anyway, I've tried this:
lastcol = .Cells(1, .Columns.Count).End(xlToLeft).Offset(0,1).Column
fvlookup = "=VLOOKUP(#1,#2,#3,False)"
fvlookup = Replace(fvlookup, "#1", rng.Address)
fvlookup = Replace(fvlookup, "#2", "[LookupFile.csv]LookupFile!$B:$I")
fvlookup = Replace(fvlookup, "#3", "5")
With .Columns(lastcol)
lrow = .range("A" & .Rows.Count).End(xlUp).Row
.Rows(lrow).Formula = fvlookup
End With
But it only places the formula into "K1" (referencing the attached image)
I've also tried selecting this value after the formula is pasted and auto filling (I know it is advised to avoid selecting ranges with vba, but I still wanted to try as a last resort), but it says it isn't allowed.
I've also tried using:
.range(lastcol & .range("A" & .Rows.Count).End(xlUp).Rows).Formula = fvlookup
But that gives me run-time error '1004': Application-defined or object-defined error. I tried creating a variable named 'lrange' and setting it similar to how I set lastcol, but no luck (it returns the same error message as above). I've also tried editing lastcol to lastcol.Column or .Columns(lastcol) in the above string, but still nothing.
I've tried researching similar questions and all of the recommendations advise defining two variables (a lastrow one and a lastcolumn one) and inserting the formula into that range, but that doesn't seem to work with what I'm using.
I feel like the process VBA is trying to execute is restricted to only being able to insert data into the entire column, or part of it, with the way I set the macro up, like it's not able to find the last column and insert all the way to the last row with the way I set it up. So I apologize if this is the case, or if I should have written it differently.
Any advise or direction anyone can provide on this topic would be much appreciated.
Thank you for your time!
Instead of looping at the end I would just use .FillDown
Cells(2, lastcol).FormulaR1C1 = fvlookup
Range(Cells(2, lastcol), Cells(lrow, lastcol)).FillDown
How about replacing your code with something like this:
Sub foo()
lastcol = .Cells(1, .Columns.Count).End(xlToLeft).Offset(0, 1).Column
fvlookup = "=VLOOKUP(#1,#2,#3,False)"
fvlookup = Replace(fvlookup, "#1", Rng.Address)
fvlookup = Replace(fvlookup, "#2", "[LookupFile.csv]LookupFile!$B:$I")
fvlookup = Replace(fvlookup, "#3", "5")
lrow = .Range("A" & .Rows.Count).End(xlUp).Row
For i = 2 To lrow
.Cells(i, lastcol).Formula = fvlookup
Next i
End Sub
This will loop from row 2 to lastrow and add the formula to lastcol.
As long as the table doesn't have an entirely blank row or column (as it shouldn't) Range("A1").CurrentRegion identifies the extent of the table. Then .Rows.Count and .Columns.Count gives you the information you need to be able to populate the adjacent column with a formula.
You can also fill the column's cells with formulas in one go, using FormulaR1C1 - provided you are careful with cell referencing. Here is an example:
Dim tableRange As Range
Dim x As Integer, y As Integer
Set tableRange = Range("A1").CurrentRegion
x = tableRange.Rows.Count
y = tableRange.Columns.Count
'fill the adjacent column with a SUM function summing across each row
Range(Cells(2, y + 1), Cells(x, y + 1)).FormulaR1C1 = "=SUM(RC[-" & y & "]:RC[-1])"
(You can also use y and 1 to give this new column a heading.)
If you need to replicate VLOOKUP with a specific (absolute) address such as $B:$I then I would first name that range and insert the name in the formula.
An example of such is:
.FormulaR1C1 = "=VLOOKUP(RC[-1],mylookup,2,FALSE)"
where mylookup is the range name and RC[-1] is referencing the cell immediately to the left of each formula.

Resources