Last Row Of Different Sheets & Duplicate Copy Paste - excel

I know the "Last Row" question has already come up several times but even when looking at existing threads I cannot find what is happening. It is the first time I write a Macro so I have only been able to get to a certain point I paste the code and ask the questions later:
Option Explicit
Sub Practice()
'Last Row Searcher
Dim Sht As Worksheet
Set Sht = ActiveSheet
Dim Last_Row As Long
With Sht
Last_Row = .Range("A9999").End(xlUp).Row
End With
'Column A to D
Sheet9.Select
Range("A2:A" & Last_Row).Copy
Sheet11.Select
Range("D" & Last_Row).Select
ActiveSheet.Paste
'Column C to F
Sheet9.Select
Range("C2:C" & Last_Row).Copy
Sheet11.Select
Range("F" & Last_Row + 1).Select
ActiveSheet.Paste
'Column E to G
Sheet9.Select
Range("E2:E" & Last_Row).Copy
Sheet11.Select
Range("G" & Last_Row + 1).Select
ActiveSheet.Paste
'Column I to L
Sheet9.Select
Range("I2:I" & Last_Row).Copy
Sheet11.Select
Range("L" & Last_Row + 1).Select
ActiveSheet.Paste
End Sub
Question 1:
When I paste what I have copied to the other worksheet it directly pastes things in the "Last_Row" from the previous worksheet instead of looking for the new "Last_Row" of the Active Sheet. Is there a way around this?
Question 2
I repeat the same code several times but with different columns, because they are not together I copy column A to D, then C to F, etc.
It is working for me, but out of curiosity, is there a way to do it all at once?

(First Empty Row After) Last Non-Empty Row
Option Explicit
Sub Practice()
'Last Row Searcher
Const frSrc As Long = 2 ' Source First Row
Const strSrc As String = "A,C, E, I" ' Source Column Letters
Const strTgt As String = "D, F,G, L" ' Target Column Letters
Dim wsSrc As Worksheet ' Source Worksheet
Dim wsTgt As Worksheet ' Target Worksheet
Dim rngSrc As Range ' Source Column Range
Dim rngTgt As Range ' Target Column Range
Dim vntS As Variant ' Source Column Array
Dim vntT As Variant ' Target Column Array
Dim lrSrc As Long ' Source Last Non-Empty Row
Dim frTgt As Long ' Target First Row After Last Non-Empty Row
Dim i As Long ' Source and Target Array Elements Counter
Dim colSrc As String ' Source Column Letter
Dim colTgt As String ' Target Column Letter
' Beware, you are using CodeNames, which are not the names on the TAB.
Set wsSrc = Sheet9
Set wsTgt = Sheet11
' Populate Column Arrays (vntS, vntT).
vntS = Split(strSrc, ","): vntT = Split(strTgt, ",")
' Loop through elements of Source (or Target) Column Array.
For i = 0 To UBound(vntS)
' Calculate Column Letter (colSrc, colTgt)
colSrc = Trim(vntS(i)): colTgt = Trim(vntT(i))
' Calculate Source Last Non-Empty Row.
lrSrc = wsSrc.Range(colSrc & wsSrc.Rows.Count).End(xlUp).Row
' Calculate Target First Row After Last Non-Empty Row.
frTgt = wsTgt.Range(colTgt & wsTgt.Rows.Count).End(xlUp).Row + 1
' Calculate Source Column Range.
Set rngSrc = wsSrc.Range(colSrc & frSrc & ":" & colSrc & lrSrc)
' Calculate Target Column Range.
Set rngTgt = wsTgt.Range(colTgt & frTgt).Resize(rngSrc.Rows.Count)
' Write values of Source Column Range to Target Column Range.
rngTgt.Value = rngSrc.Value
Next
End Sub
EDIT:
Sub Practice2()
'Last Row Searcher
Const frSrc As Long = 2 ' Source First Row
Const strSrc As String = "A,C, E, I" ' Source Column Letters
Const strTgT As String = "D, F,G, L" ' Target Column Letters
Dim wsSrc As Worksheet ' Source Worksheet
Dim wsTgt As Worksheet ' Target Worksheet
Dim rngSrc As Range ' Source Column Range
Dim rngTgt As Range ' Target Column Range
Dim vntS As Variant ' Source Column Array
Dim vntT As Variant ' Target Column Array
Dim lrSrc As Long ' Source Last Non-Empty Row
Dim frTgt As Long ' Target First Row After Last Non-Empty Row
Dim i As Long ' Source and Target Array Elements Counter
Dim colSrc As String ' Source Column Letter
Dim colTgt As String ' Target Column Letter
' Beware, you are using CodeNames, which are not the names on the TAB.
Set wsSrc = Sheet9
Set wsTgt = Sheet11
' Populate Column Arrays (vntS, vntT).
vntS = Split(strSrc, ",")
vntT = Split(strTgT, ",")
' Calculate Target First Row After Last Non-Empty Row.
frTgt = wsTgt.Range(Trim(vntT(0)) & wsTgt.Rows.Count).End(xlUp).Row + 1
' Loop through elements of Source (or Target) Column Array.
For i = 0 To UBound(vntS)
' Calculate Column Letter (colSrc, colTgt)
colSrc = Trim(vntS(i)): colTgt = Trim(vntT(i))
' Calculate Source Last Non-Empty Row.
lrSrc = wsSrc.Range(colSrc & wsSrc.Rows.Count).End(xlUp).Row
' Calculate Source Column Range.
Set rngSrc = wsSrc.Range(colSrc & frSrc & ":" & colSrc & lrSrc)
' Calculate Target Column Range.
Set rngTgt = wsTgt.Range(colTgt & frTgt).Resize(rngSrc.Rows.Count)
' Write values of Source Column Range to Target Column Range.
rngTgt.Value = rngSrc.Value
Next
End Sub

You need to set define the "last row" more clearly. In your case, I believe what you want is to find the last row of the source data AND then paste it after the last row of your destination sheet. So try something like this:
Dim srcWS As Worksheet
Set srcWS = Sheet9
Dim dstWS As Worksheet
Set dstWS = Sheet11
Dim srcLastRow As Long
With srcWS
srcLastRow = .Cells(.Rows.Count, "A").End(xlUp).Row
End With
Dim dstLastRow As Long
With dstWS
dstLastRow = .Cells(.Rows.Count, "D").End(xlUp).Row
End With
srcWS.Range("A2:A" & srcLastRow).Copy
dstWS.Range("D" & dstLastRow).Paste
No Select or ActiveSheet is necessary (which you should avoid whenever you can).

Adding another answer here because my previous answer was incomplete (and it's been bothering me since yesterday!). Since this is a repetitive bit of code, I would separate the column-copy into it's own sub. Your logic becomes very simple in your main routine.
Option Explicit
Sub test()
CopyMyColumn Sheet1.Range("A1").EntireColumn, Sheet1.Range("D1").EntireColumn
CopyMyColumn Sheet1.Range("C1").EntireColumn, Sheet1.Range("F1").EntireColumn
CopyMyColumn Sheet1.Range("E1").EntireColumn, Sheet1.Range("G1").EntireColumn
CopyMyColumn Sheet1.Range("I1").EntireColumn, Sheet1.Range("L1").EntireColumn
End Sub
Private Sub CopyMyColumn(ByRef srcColumn As Range, ByRef dstColumn As Range)
'--- copies the source column from row 2 to the end of the data, to
' the destination column, appending to the end of the existing data
Dim srcLastRow As Long
With srcColumn
srcLastRow = .Cells(.Rows.Count, 1).End(xlUp).Row
End With
Dim dstLastRow As Long
With dstColumn
dstLastRow = .Cells(.Rows.Count, 1).End(xlUp).Row
End With
Dim src As Range
Dim dst As Range
Set src = srcColumn.Cells(2, 1).Resize(srcLastRow, 1)
Set dst = dstColumn.Cells(1, 1).Offset(dstLastRow, 0).Resize(srcLastRow, 1)
dst.Value = src.Value
End Sub

Related

Select range of cells based on existence of a value found in another cell

I'm new to vba and I'm trying to write a script where I want to select a Range of columns based on the existence of a value in another column. So for example in the matrix below, I want to be able to select the BC range where A column is not blank, which is B1:C3
A B C
1 12345
2 54321
3 39284
4 <blank>
5 <blank>
Reference a Range
Range.End property
Range.EntireRow property
Error in finding last used cell in Excel with VBA
Option Explicit
Sub ReferenceRangeQuick()
Dim rg As Range
Set rg = Range("A1:A" & Range("A" & Rows.Count) _
.End(xlUp).Row).EntireRow.Columns("B:C")
Debug.Print rg.Address
End Sub
Sub ReferenceRangeStudy()
Const lrCol As String = "A"
Const sCols As String = "B:C"
Const fRow As Long = 1
Dim ws As Worksheet: Set ws = ActiveSheet ' improve
' Last Row
' Note that this will return 1 even if there is no data in the column.
Dim lRow As Long: lRow = ws.Cells(ws.Rows.Count, lrCol).End(xlUp).Row
If lRow < fRow Then Exit Sub
Debug.Print "Last Row Number: " & lRow
' Last Row Column Range
Dim lrcrg As Range
Set lrcrg = ws.Range(ws.Cells(fRow, lrCol), ws.Cells(lRow, lrCol))
Debug.Print "Last Row Column Range Address: " & lrcrg.Address(0, 0)
' Source Range
Dim srg As Range: Set srg = lrcrg.EntireRow.Columns(sCols)
Debug.Print "Source Range Address: " & srg.Address(0, 0)
End Sub

After initial macro run, move source range to next row and copy

I was recently assisted by a member of this community in addressing how I should build out a macro for my project. The following macro works precisely as I would like it to. However, there is a manual dependency that I am trying to correct.
The source range is predefined as specific cell references (e.g. A10, B10, C10, F10...) After I run this macro, I would like the source range to move down to the next row so that the next time the macro is called, it copies A11, B11, C11, F11...
Please let me know if this is possible. The following is the VBA code I've been using:
Public Sub Update_Project_1()
' Set a reference to the source sheet
Dim sourceSheet As Worksheet
Set sourceSheet = ThisWorkbook.Worksheets("High Level Tracker")
' Set a reference to the target sheet
Dim targetSheet As Worksheet
Set targetSheet = ThisWorkbook.Worksheets("Project 1 Detailed Tracker")
' Set a reference to the source range
Dim sourceRange As Range
Set sourceRange = sourceSheet.Range("A10,B10,C10,F10,H10")
' Get last row in target sheet
Dim lastRow As Long
lastRow = targetSheet.Cells(targetSheet.Rows.Count, "A").End(xlUp).Row
' Loop through each cell in source range
Dim sourceCell As Range
For Each sourceCell In sourceRange.Cells
' Output values from source range into next empty row in target
Dim columnCounter As Long
targetSheet.Range("A" & lastRow + 1).Offset(, columnCounter).Value = sourceCell.Value
columnCounter = columnCounter + 1
Next sourceCell
End Sub
Any help would be kindly appreciated, thanks!
You can find the last empty row in the source sheet and then copy the values to the target sheet
Public Sub Update_Project_1()
' Set a reference to the source sheet
Dim sourceSheet As Worksheet
Set sourceSheet = ThisWorkbook.Worksheets("High Level Tracker")
' Set a reference to the target sheet
Dim targetSheet As Worksheet
Set targetSheet = ThisWorkbook.Worksheets("Project 1 Detailed Tracker")
' Get last row in source sheet
Dim lastRowSource As Long
lastRowSource = sourceSheet.Cells(sourceSheet.Rows.Count, "A").End(xlUp).Row
' Define the source range address
Dim sourceRangeAddress As String
sourceRangeAddress = "A<r>,B<r>,C<r>,F<r>,H<r>"
' Replace next row in source rane
sourceRangeAddress = Replace(sourceRangeAddress, "<r>", lastRowSource)
' Set a reference to the source range
Dim sourceRange As Range
Set sourceRange = sourceSheet.Range(sourceRangeAddress)
' Get last row in target sheet
Dim lastRowTarget As Long
lastRowTarget = targetSheet.Cells(targetSheet.Rows.Count, "A").End(xlUp).Row
' Loop through each cell in source range
Dim sourceCell As Range
For Each sourceCell In sourceRange.Cells
' Output values from source range into next empty row in target
Dim columnCounter As Long
targetSheet.Range("A" & lastRowTarget + 1).Offset(, columnCounter).Value = sourceCell.Value
columnCounter = columnCounter + 1
Next sourceCell
End Sub
Not the cleanest one, but it may help.
At start of your code, just add:
Dim ThisRow As Long
ThisRow = InputBox("What row?", , 10)
This will ask user in every execution of macro a row number (default value =10)
Then replace line
Set sourceRange = sourceSheet.Range("A10,B10,C10,F10,H10")
with
Set sourceRange = sourceSheet.Range("A" & ThisRow & ",B" & ThisRow & ",C" & ThisRow & ",F" & ThisRow & ",H" & ThisRow)
This way, every execution will allow you to choose what the target row, without editing code manually.
Your current cell is called ActiveCell. In order to go to another cell, you might use the Offset() function.
So, both combined give following line of source code:
ActiveCell.Offset(1,0).Activate
This means: take the current active cell, go one row further but no columns (1,0), and activate that cell.

How to copy and transpose headers to another sheet?

I'm trying to copy and transpose the headers from my source worksheet into my target sheet to use as mappings.
My code copies the row below the one I want (Row 1).
Sub Create_Mappings()
Dim source_sht As Worksheet
Dim target_sht As Worksheet
Dim src_raw_rng As Range 'Ranges for headings from raw_data
Dim trg_raw_rng As Range
Dim src_map_rng As Range 'Ranges for mapping headings
Dim trg_map_rng As Range
Dim last_row As Long
Dim last_column As Long
Set source_sht = ThisWorkbook.Worksheets(6)
Set target_sht = ThisWorkbook.Worksheets(4)
'Determine last row of data in Mappings sheet and last column in first row of Raw_Data
last_row = target_sht.Cells(target_sht.Rows.Count, "C").End(xlUp).Row
last_column = source_sht.Cells(source_sht.Range("A1"), source_sht.Columns.Count).End(xlToLeft).Column
'Clear mappings
Set src_raw_rng = source_sht.Range(source_sht.Cells(1, 1), source_sht.Cells(1, last_column))
Set trg_raw_rng = target_sht.Range(Range("InpVarStart"), target_sht.Cells(last_row + 1, 3))
trg_raw_rng.Clear
src_raw_rng.Copy
trg_raw_rng.PasteSpecial Transpose:=True
End Sub
Try this. Please note the comments starting with '*
Sub Create_Mappings()
Dim source_sht As Worksheet
Dim target_sht As Worksheet
Dim src_raw_rng As Range 'Ranges for headings from raw_data
Dim trg_raw_rng As Range
Dim src_map_rng As Range 'Ranges for mapping headings
Dim trg_map_rng As Range
Dim last_row As Long
Dim last_column As Long
Set source_sht = Sheet6 ' ThisWorkbook.Worksheets(6)
Set target_sht = Sheet4 ' ThisWorkbook.Worksheets(4)
'Determine last row of data in Mappings sheet and last column in first row of Raw_Data
last_row = target_sht.Cells(target_sht.Rows.Count, "C").End(xlUp).Row
'* changed source_sht.Range("A1") to 1
'* you can use source_sht.Range("A1").Row, but 1 is better since you are hard-coding "A1"
last_column = source_sht.Cells(1, source_sht.Columns.Count).End(xlToLeft).Column
'Clear mappings
Set src_raw_rng = source_sht.Range(source_sht.Cells(1, 1), source_sht.Cells(1, last_column))
Set trg_raw_rng = target_sht.Range(Range("InpVarStart"), target_sht.Cells(last_row + 1, 3))
trg_raw_rng.Clear
src_raw_rng.Copy
'* Use first cell of target range
trg_raw_rng.Cells(1, 1).PasteSpecial Transpose:=True
trg_raw_rng.Select
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

Pasting to one column based on criteria in another

I am trying to paste a range of formulas from one worksheet to another.
In the target worksheet, the code looks for criteria in column A, then if met, pasts in column H. It goes from the last used cell up.
I am sure this is entry level stuff but if someone can assist that would be greatly appreciated.
Code below
Sub Step8()
'Copies cells from worksheet called "Bi-Weekly"
Worksheets("Bi-Weekly").Activate
Range("H16:BK16").Copy
'Go to target worksheet called "Report"
Worksheets("Report").Activate
Dim lRow As Long
'find last row
lRow = Cells(Rows.Count, 1).End(xlUp).Row
'Loop from the last row to the first (finishing at row 17)
For i = lRow To 17 Step -1
'Where column A = "No", paste copied cells to column H (to BK) from original worksheet
If ActiveSheet.Range("A" & i).Value = "No" Then
ActiveSheet.Range("H" & i).Paste
End If
Next i
End Sub
Copy Formulas
The Code
Sub Step8()
Const cSource As String = "Bi-Weekly" ' Source Worksheet Name
Const cRange As String = "H16:BK16" ' Source Range Address
Const cTarget As String = "Report" ' Target Worksheet Name
Const cColCrit As Variant = 1 ' Target Criteria Column Letter/Number
Const cColTgt As Variant = "H" ' Target Column Letter/Number
Const cfRow As Long = 17 ' Target First Row
Const cCrit As String = "No" ' Target Criteria
Dim rng As Range ' Source Range
Dim lRow As Long ' Target Last Row Number
Dim i As Long ' Target Worksheet Row Counter
' Create a reference to the Source Range (rng).
Set rng = ThisWorkbook.Worksheets(cSource).Range(cRange)
' In Target Worksheet
With ThisWorkbook.Worksheets(cTarget)
' Calculate Last Row Number (lRow)
' from Target Criteria Column (cColCrit).
lRow = .Cells(.Rows.Count, cColCrit).End(xlUp).Row
' Loop through rows (cells) of Target Worksheet starting from First Row.
For i = cfRow To lRow
' When the cell at the intersection of the current row (i)
' and the Target Criteria Column (cColCrit) contains
' the Target Criteria (cCrit).
If .Cells(i, cColCrit).Value = cCrit Then
' Copy Source Range (rng) to the cell at the intersection
' of the current row (i) and Target Column (cColTgt).
rng.Copy .Cells(i, cColTgt)
End If
Next
End With
End Sub
No Constants Version
Sub Step8NoConstants()
Dim rng As Range ' Source Range
Dim lRow As Long ' Target Last Row Number
Dim i As Long ' Target Worksheet Row Counter
' Create a reference to the Source Range (rng).
Set rng = ThisWorkbook.Worksheets("Bi-Weekly").Range("H16:BK16")
' In Worksheet "Report".
With ThisWorkbook.Worksheets("Report")
' Calculate Last Row Number (lRow) from column 1 ("A").
lRow = .Cells(.Rows.Count, 1).End(xlUp).Row
' Loop through rows (cells) of worksheet "Report" starting from row 17.
For i = 17 To lRow
' When the cell at the intersection of the current row (i)
' and column 1 ("A") contains "No".
If .Cells(i, 1).Value = "No" Then
' Copy Source Range (rng) to the cell at the intersection
' of the current row (i) and column "H".
rng.Copy .Cells(i, "H")
End If
Next
End With
End Sub

Resources