How to subtract two dynamic ranges and paste it to another cell - excel

I have made a macro that copies two dynamic table columns from one worksheet to another. On the Second worksheet I want to subtract those two columns and paste the result on a separate column/vector. All of this needs to be dynamic since I plan on running the macro once a day.
The closest I have come is the following code:
Sub Makro2()
Dim ws_3 As Worksheet
Set ws_3 = ThisWorkbook.Worksheets(2)
Application.CutCopyMode = False
ws_3.Range("E3:E400").FormulaR1C1 = "=RC[-2]-RC[-1]"
End Sub
So all I need in reality is for E3:E400 to be dynamic since the range of the other two columns change every day.
PS. Rather new at VBA.

This is just basic, ensure you declare your variable.
Dim lRow As Long
lRow = Range("D" & Rows.Count).End(xlUp).Row
Range("E3:E" & lRow).FormulaR1C1 =

You could try:
Option Explicit
Sub test()
Dim wsSource As Worksheet, wsDestination As Worksheet
Dim LastRow1 As Long, LastRow2 As Long, rng1 As Range, rng2 As Range, LastColumn As Long
With ThisWorkbook
Set wsSource = .Worksheets("Sheet1") '<- Data appears here
Set wsDestination = .Worksheets("Sheet2") '<- Data will be copy here
End With
With wsSource
'Let's say the two columns we want to copy is column A & B. Find Last row of A & B
LastRow1 = .Cells(.Rows.Count, "A").End(xlUp).Row
LastRow2 = .Cells(.Rows.Count, "B").End(xlUp).Row
'Create the ranges you want to copy
Set rng1 = .Range("A1:A" & LastRow1)
Set rng2 = .Range("B1:B" & LastRow2)
End With
With wsDestination
'Paste column after the last column of row 1. Find last column row 1
LastColumn = .Cells(1, .Columns.Count).End(xlToLeft).Column
rng1.Copy
.Cells(1, LastColumn + 1).PasteSpecial xlPasteValues
rng2.Copy
.Cells(1, LastColumn + 2).PasteSpecial xlPasteValues
End With
Application.CutCopyMode = False
End Sub

Related

Looking for a way to Autofill Using a Variable Range

I'm looking for a way to autofill my formula down to the last row in the dataset (which is variable) using a range which is also variable. I have highlighted my issue below at the bottom.
Here is the code that I have now:
Sub MissingData()
Dim LastRow As Long
Dim LastCol As Long
Set ws = Worksheets("Insert Data")
With ws
Last Row = .Cells(.Rows.Count, 1).End(xlUp).Row
Last Col = .Cells(1, .Columns.Count).End(xlToLeft).Column
'Inserting Column Header next to the last column in the data set in row 1"
.Cells(1, LastCol + 1).Value = "Header"
'Inserting Formula next ot the last column in the data set in row 2"
.Cells(2, LastCol + 1).Formula = "=iferror(AJ2,""YES"")"
End With
Dim FoundCell As Range
'Looking for the Last Row in the Dataset"
'Column A:A will always be populated with data and will be the driver
'for how many rows are in the data set"
LR = Worksheets("Insert Data").Range("A:A").End(xlDown).Row
With ws
'I set this and then called it using select because my range above
'and the location of this cell could be variable"
Set FoundCell = .Cells(2, LastCol + 1)
FoundCell.Select
'Here lies my issue. Using this syntax the formula is filled all the way
'to the last row available in Excel which is like 1 million something.
'I just need it filled to the last now that i set above"
Selection.AutoFill Destination:=Range(ActiveCell, ActiveCell.End(xlDown))
End With
End Sub
A better alternative to AutoFill is to enter the formula in the entire range in one go. Is this what you are trying?
Option Explicit
Sub MissingData()
Dim LastRow As Long
Dim LastCol As Long
Dim ws As Worksheet
Dim LastColName As String
Set ws = Worksheets("Insert Data")
With ws
'~~> Find last row
LastRow = .Cells(.Rows.Count, 1).End(xlUp).Row
'~~> Find last column and add 1 to it
LastCol = .Cells(1, .Columns.Count).End(xlToLeft).Column + 1
'~~> Get Column name from column number
' https://stackoverflow.com/questions/10106465/excel-column-number-from-column-name
LastColName = Split(.Cells(, LastCol).Address, "$")(1)
'~~> Add header
.Range(LastColName & 1).Value = "Header"
'~~> Add the formula in the entire range in ONE GO
' Example: Range("D2:D" & LastRow).Formula = "=IFERROR(AJ2,""YES"")"
.Range(LastColName & 2 & ":" & LastColName & LastRow).Formula = "=IFERROR(AJ2,""YES"")"
End With
End Sub

Copy a range in column using Excel VBA

I am trying to add a button, that adds a new column after the last column with values. This works.
Now I want to copy values to the new column. Values shall be copied from the last column from row 32 to the last one with a value in column A.
Right now Ihave a code for copying the whole column. How do I concentrate on the specific range?
Sub AddMeeting()
Dim ws As Worksheet
Dim lastcol As Long
Set ws = ActiveSheet
lastcol = ws.Cells(32, ws.Columns.Count).End(xlToLeft).Column
Columns(lastcol).Copy Destination:=Columns(lastcol + 1)
Range ((Cells.Columns.Count.End(xlLeft)) & Range(32)), (lastcol + 1) & Cells.Rows.Count.End(xlUp)
Application.CutCopyMode = False
End Sub
Values shall be copied from the last column from row 32 to the last one with a value in column A
Is this what you are trying?
Option Explicit
Sub Sample()
Dim ws As Worksheet
Dim lRow As Long, lCol As Long
Dim LastColumn As String
Dim rngToCopy As Range
'~~> Set this to the relevant worksheet
Set ws = Sheet1
With ws
'~~> Find last row in Col A
lRow = .Range("A" & .Rows.Count).End(xlUp).Row
'~~> Find last column in row 32
lCol = .Cells(32, .Columns.Count).End(xlToLeft).Column
'~~> Get Column Name from column number
' https://stackoverflow.com/questions/10106465/excel-column-number-from-column-name
LastColumn = Split(Cells(, lCol).Address, "$")(1)
Set rngToCopy = .Range("A32:" & LastColumn & lRow)
Debug.Print rngToCopy.Address
With rngToCopy
'
' Do what you want here
'
End With
End With
End Sub

(Copy if) Multiple Variables

I wanted to copy data from one sheet to another. The selection part is according to date and specific value of column.
enter image description here
I tried this code from internet. So the basic logic is if 2 condition are met then copy the row. However its not working.
It actually working first when only one condition are written, when the second one written, the VBA did not do anything
Sub CopyRowsAcross()
Dim i As Integer
Dim ws1 As Worksheet: Set ws1 = ThisWorkbook.Sheets("Clean_Sheet")
Dim ws2 As Worksheet: Set ws2 = ThisWorkbook.Sheets("Daily_Report")
For i = 2 To ws1.Range("P65536").End(xlUp).Row
If ws1.Cells(i, 1) = "DOWNY S.FRESH 900ML" and ws2.Range ("C2") = ws1.Cells(i,3) Then
ws1.Rows(i).Copy ws2.Rows(ws2.Cells(ws2.Rows.Count, 2).End(xlUp).Row + 1)
End If
Next i
End Sub
the ws2.Range("C2") are selected date written in cell C2 in the sheet.
The result are the row copied based on this 2 criteria
This works assuming both your data in worksheet 1 are really dates and the filter in C2 is a date also:
Option Explicit
Sub CopyRowsAcross()
Dim LastRow As Long, lrow As Long
Dim ws1 As Worksheet: Set ws1 = ThisWorkbook.Sheets("Clean_Sheet")
Dim ws2 As Worksheet: Set ws2 = ThisWorkbook.Sheets("Daily_Report")
Dim DateFilter As Date
With ws2
DateFilter = .Cells(2, 3)
lrow = .Cells(.Rows.Count, 1).End(xlUp).Row + 1
End With
With ws1
LastRow = .Cells(.Rows.Count, 1).End(xlUp).Row
.Range("A1:C" & LastRow).AutoFilter Field:=1, Criteria1:="DOWNY S.FRESH 900ML"
.Range("A1:C" & LastRow).AutoFilter Field:=3, Criteria1:=Format(DateFilter, "dd-Mmm-yy")
LastRow = .Cells(.Rows.Count, 1).End(xlUp).Row
If LastRow > 1 Then
.Range("A2:C" & LastRow).SpecialCells(xlCellTypeVisible).Copy ws2.Cells(lrow, 1)
End If
.AutoFilterMode = False
End With
End Sub
Instead of looping (Time consuming) you could just filter the data you need and copy it all a t once.

How to specify a sheet to determine 'lastrow'?

I am trying to determine 'lastrow' of the sheet that the macro is being run on.
I am working with two sheets. Sheet1 has about 150 rows of data and Sheet 2 only has two.
I expected that when I selected Sheet2 and assigned lastrow that it would take the count of rows from Sheet2, instead it is storing the row count from sheet1.
sub row_count()
dim lastrow as long
lastrow = Range("A" & Rows.Count).End(xlUp).row
if lastrow = 150 then
with sheets("sheet2")
.select
lastrow = Range("A" & Rows.Count).End(xlUp).row
msgbox lastrow '<----- Always returns the value of sheet1 instead of sheet2.
end with
end sub
You're using a With block, which means the program sees anything between 'With' and 'End With' as being prefixed by whatever you put after the keyword 'With', so to modify your code in place for sheet2 only:
Sub row_count()
Dim lastrow As Long
lastrow = Sheets("sheet2").Range("A" & Rows.Count).End(xlUp).Row
If lastrow = 150 Then
With Sheets("sheet2")
' .Select = Sheets("sheet2").Select
.Select
' .Range = Sheets("sheet2").Range
lastrow = .Range("A" & Rows.Count).End(xlUp).Row
MsgBox lastrow
End With
End Sub
If you want the code to run on the currently visible sheet you should change it to use the ActiveSheet property:
Sub row_count()
Dim lastrow As Long
lastrow = ActiveSheet.Range("A" & Rows.Count).End(xlUp).Row
If lastrow = 150 Then
With ActiveSheet ' use the currently visible sheet
.Select
lastrow = .Range("A" & Rows.Count).End(xlUp).Row
MsgBox lastrow
End With
End Sub
However, there are some ways to improve this code: for flexibility you could pass the worksheet as a parameter. Also, your End function might return the first used row if there is already data in the last used row (it's the same as clicking in the last row and pressing Ctrl & the up arrow, so you should start in a cell below that). Lastly, you do not need to select the sheet to get the last row:
Sub GetRowCounts()
row_count Sheets("sheet1")
row_count Sheets("sheet2")
End Sub
Sub row_count(ws As Worksheet)
Dim lastrow As Long
lastrow = ws.Range("A1000000").End(xlUp).Row
MsgBox lastrow
End Sub
I think these examples are the easiest to follow.
Sub FindingLastRow()
'PURPOSE: Different ways to find the last row number of a range
'SOURCE: www.TheSpreadsheetGuru.com
Dim sht As Worksheet
Dim LastRow As Long
Set sht = ThisWorkbook.Worksheets("Sheet1")
'Ctrl + Shift + End
LastRow = sht.Cells(sht.Rows.Count, "A").End(xlUp).Row
'Using UsedRange
sht.UsedRange 'Refresh UsedRange
LastRow = sht.UsedRange.Rows(sht.UsedRange.Rows.Count).Row
'Using Table Range
LastRow = sht.ListObjects("Table1").Range.Rows.Count
'Using Named Range
LastRow = sht.Range("MyNamedRange").Rows.Count
'Ctrl + Shift + Down (Range should be first cell in data set)
LastRow = sht.Range("A1").CurrentRegion.Rows.Count
End Sub
https://www.thespreadsheetguru.com/blog/2014/7/7/5-different-ways-to-find-the-last-row-or-last-column-using-vba
Keep an open mind though, there are lots of ways to do this same kind of thing.
If this statement...
lastrow = Range("A" & Rows.Count).End(xlUp).row
... really always returns the last row of Sheet1 instead of last row of Sheet2, then that is because you are looking at your Workbook open at Sheet1 all the time.
Whenever you have a Range or Cells statement like the above ( Range(...) ) without an explicit reference to a Worksheet, then ActiveSheet is what it is referenced to.
So to avoid that, this is what you do:
Dim Sht_1 as Worksheet
Dim Sht_2 as Worksheet
Dim Sht_1_Lastrow as Long
Dim Sht_2_Lastrow as Long
Set Sht_1 = ActiveWorkbook.Worksheets(1)
Set Sht_2 = ActiveWorkbook.Worksheets(2)
Sht_1_Lastrow = Sht_1.Range("A" & Sht_1.Rows.Count).End(xlUp).Row
Sht_2_Lastrow = Sht_2.Range("A" & Sht_2.Rows.Count).End(xlUp).Row
or
Sht_1_Lastrow = Sht_1.Cells(Sht_1.Rows.Count, "A").End(xlUp).Row
Sht_2_Lastrow = Sht_2.Cells(Sht_2.Rows.Count, "A").End(xlUp).Row
Above code block highlights the difference that makes a LastRow Variable explicitly tied to a certain Worksheet...
This way your problem cannot happen...

filter on criteria then copy and paste at bottom of same worksheet

I'm new to VBA and after much searching, i can't get the code working correctly. I am trying to filter/select anything which has the value 313 in column B AND the values 1 OR 2 in column C then copy all the relevant rows with the data from all columns (A-N) at the bottom of the same worksheet. The worksheet does not have a set number of rows and 313 is not always in the same set of cells. I have tried the following but the code seems to be pasting in 'A2' rather than the selection at the bottom. Any help would be much appreciated.
Sub CopyPartOfFilteredRange()
Dim ws1 As Worksheet
Dim filterRange As range
Dim copyRange As range
Dim lastRow As Long
Set ws1 = ThisWorkbook.Sheets("Sheet 1")
ws1.AutoFilterMode = False
lastRow = ws1.range("A" & ws1.Rows.Count).End(xlUp).Row
Set filterRange = ws1.range("A1:N" & lastRow)
Set copyRange = ws1.range("A2:N" & lastRow)
filterRange.AutoFilter Field:=2, Criteria1:="313"
filterRange.AutoFilter Field:=3, Criteria1:="=1", _
Operator:=xlAnd, Criteria2:="=2"
lastRow = ws1.Cells(Rows.Count, 1).End(xlUp).Offset(1, 0).Row
ws1.Cells(lastRow, 1).Select
ws1.Paste
ws1.AutoFilterMode = False
End Sub
you must:
change xlAnd into xlOr
increase lastRow of 1 to reference the cell to paste in
use SpecialCells(xlCellTypeVisible) to select filtered cells (if any!)
try his
Option Explicit
Sub CopyPartOfFilteredRange()
Dim lastRow As Long
With ThisWorkbook.Sheets("Sheet 1")
.AutoFilterMode = False
lastRow = .Range("A" & .Rows.Count).End(xlUp).row
With .Range("A1:N" & lastRow)
.AutoFilter Field:=2, Criteria1:="313"
.AutoFilter Field:=3, Criteria1:="1", Operator:=xlOr, Criteria2:="2"
If Application.WorksheetFunction.Subtotal(103, .Cells.Resize(, 1)) > 1 Then 'count visible cells in column "A" other than the header
.Offset(1).Resize(.Rows.Count - 1).SpecialCells(xlCellTypeVisible).Copy .Cells(lastRow + 1, 1)
End If
End With
.AutoFilterMode = False
End With
End Sub
I believe that because you are redefining the last row after a filter, using xlUp will miss the last row since it may be hidden in the filter. I would suggest using
lastRow = lastRow + 1
since you already have the last row of the range defined and you just want to past one row below that.
Your second filter, by the way, will filter on nothing because no cell will be both equal to 1 and equal to 2. Not sure what you want there. In any case, like I said in my comment, I don't believe you are copying anything, so you will need
filterRange.Copy
after the filter. I am not sure I would recommend copying and pasting like this, but I am going to try to just modify your code instead of rewriting it.
Also, I don't believe that
Set copyRange = ws1.range("A2:N" & lastRow)
is needed at all and can be deleted.
This is what I have in full
Sub CopyPartOfFilteredRange()
Dim ws1 As Worksheet
Dim filterRange As Range
Dim lastRow As Long
Set ws1 = Worksheets("Sheet1")
ws1.AutoFilterMode = False
lastRow = ws1.Range("A" & ws1.Rows.Count).End(xlUp).Row
Set filterRange = ws1.Range("A1:N" & lastRow)
filterRange.AutoFilter Field:=2, Criteria1:="313"
filterRange.Copy
lastRow = lastRow + 1
ws1.Cells(lastRow, 1).Select
ws1.Paste
ws1.AutoFilterMode = False
End Sub

Resources