Transfer rows from one sheet to another starting with the second Column - excel

I have a membership roster that I am keeping for a chapter in a club. Rather than delete members who are no longer in the chapter, I decided to try and create a macro that looks at the Chapter Roster Master sheet in column A (Still in Chapter?) for a "yes" value and then transfers the all the rows with the yes value to another sheet called "Chapter Roster Actual".
The macro works but I would like to only transfer columns B through O and not include Column A.
I realize the one line actually tells the macro to copy the "entire row" and I have tried to have it copy only a range but in doing that, it disregards the request to only copy rows where column A has a 'yes' value. I have the range line in there as well so you could see what I tried.
I also need to figure out how to not append the rows to previously copied rows. So, I guess it should clear the rows previously populated and then write the new rows.
Here is the macro:
Sub ActualRoster()
Dim myRow, LastRow
myworksheet = "Chapter Roster Master"
LastRow = Sheets(myworksheet).Range("A" & Rows.Count).End(xlUp).Row
For myRow = 3 To LastRow
If Sheets(myworksheet).Cells(myRow, "A").Value = "Yes" Then
Sheets(myworksheet).Cells(myRow, "A").EntireRow.Copy Destination:=Sheets("Chapter Roster Actual").Range("A" & Rows.Count).End(xlUp).Offset(1)
'Sheets(myworksheet).Range("B3:O32").Copy Destination:=Sheets("Chapter Roster Actual").Range("A3:O32").End(xlUp).Offset(1)*
End If
Next myRow
End Sub

In what you tried, you are copying all the rows starting from 3 right upto 32 even if only current row is 'Yes'
The following works fine
Sub ActualRoster()
Dim myRow, LastRow
myworksheet = "Chapter Roster Master"
Sheets("Chapter Roster Actual").Range("A3").CurrentRegion.Offset(2,0).ClearContents
Sheets(myworksheet).Activate
LastRow = Sheets(myworksheet).Range("A" & Rows.Count).End(xlUp).Row
For myRow = 3 To LastRow
If Sheets(myworksheet).Cells(myRow, "A").Value = "Yes" Then
Sheets(myworksheet).Range(Cells(myRow,"B"),Cells(myRow,"O")).Copy Destination:=Sheets("Chapter Roster Actual").Range("A" & Rows.Count).End(xlUp).Offset(1)
End If
Next myRow
End Sub
As suggested in a comment, you can also try filter the Master data and copy all required data in one shot. As a starting point, record a macro and you will get a feel of how that can be done. Come back to refine recorded code.

You can use below code If you want to try using the filter instead of iterating over all the records. You can check which works best for you and use.
Sub ActualRoster()
Dim myRow, LastRow
myworksheet = "Chapter Roster Master"
LastRow = Sheets(myworksheet).Range("A" & Rows.Count).End(xlUp).Row
Range("A2").Select
Range(Selection, Selection.End(xlToRight)).Select
Selection.AutoFilter
Range("A2").Select
ActiveSheet.Range("A2", Range("A2").End(xlToRight)).AutoFilter Field:=1, Criteria1:="Yes"
Range("A2").End(xlToLeft).Select
ActiveCell.Offset(1, 0).Select
Range(Selection, Selection.End(xlToRight)).Select
Range(Selection, Selection.End(xlDown)).Select
Selection.Copy Destination:=Sheets("Chapter Roster Actual").Range("A" & Rows.Count).End(xlUp).Offset(1)
End Sub
Note: There might be more optimized code for this scenario too
Tip: You can learn how macro works by opening the VBA along with Excel (in side by side mode), record the macro and observe the code generated.

Related

Insert sequential number for each row with a record

I'm very new to VBA and learning through code I find on the internet, and also using macros to see code.
I have an imported xls with three columns of data. I have code that does the following:
Inserts a new column A
Deletes column B
Delete rows with no data
Inserts two columns
So far - okay. What I am then trying to do is insert a number starting at 1 in column A1 and sequentially filling in until all rows with records have a number. I used a macro to see the code, but the range will vary (i.e. there are not always 52 rows in my import).
Is there a way to make this dynamic by only applying a number where there is data in the row (Column B will always have data)?
Thanks in advance - all help greatly appreciated!
Sub DeleteBlankRows()
Dim x As Long
Dim lastRow As Long
Dim A As Long
' INSERT A NEW COLUMN A FOR NUMERICAL SEQUENCE
Columns("A:A").Select
Selection.Insert Shift:=xlToRight, CopyOrigin:=xlFormatFromLeftOrAbove
'DELETE ALL BLANK ROWS
With ActiveSheet
For x = .Cells.SpecialCells(xlCellTypeLastCell).Row To 1 Step -1
If WorksheetFunction.CountA(.Rows(x)) = 0 Then
ActiveSheet.Rows(x).Delete
End If
Next
End With
'add two new columns for population
ActiveCell.Offset(0, 2).Columns("A:A").EntireColumn.Select
Selection.Delete Shift:=xlToLeft
ActiveCell.Columns("A:B").EntireColumn.Select
Selection.Insert Shift:=xlToRight, CopyOrigin:=xlFormatFromLeftOrAbove
Selection.NumberFormat = "#"
'code to enter a sequential number starting at 1 for every row that has a record
ActiveSheet.Range("A1").Select
ActiveCell.Select
ActiveCell.FormulaR1C1 = "1"
ActiveCell.Select
Selection.AutoFill Destination:=ActiveCell.Range("A1:A52"), Type:= _
xlFillSeries
ActiveCell.Range("A1:A52").Select
ActiveWindow.SmallScroll Down:=15
End Sub
There are a lot of stuff to improve your my code, but this should get you started
Some things to begin:
Use option explicit at the top of your modules so you don't have unexpected behavior with undefined variables
Always indent your code (see www.rubberduckvba.com a free tool that helps you with that)
Try to separate your logic defining variables and the reusing them
Name your variables to something meaningful and easy to unterstand (avoid x or r)
Write the code steps in plain English first, then develop it in VBA
Check the code's comments, and adapt it to fit your needs
Code
Public Sub PrepareFormat()
' Set a target sheet
Dim targetSheet As Worksheet
Set targetSheet = ActiveSheet ' This could be always the same sheet. If so, replace activesheet with thisworkbook.Sheets("NameOfTheSheet")
' Insert a new column for numerical sequence
targetSheet.Columns("A:A").Insert shift:=xlToRight, CopyOrigin:=xlFormatFromLeftOrAbove
' Delete all blank rows
Dim counter As Long
With targetSheet
For counter = .Cells.SpecialCells(xlCellTypeLastCell).Row To 1 Step -1
If WorksheetFunction.CountA(.Rows(counter)) = 0 Then
.Rows(counter).Delete
End If
Next counter
End With
' Add two new columns for population (this next lines would make column B empty, so filling sequentally would not work below
'targetSheet.Columns("D:D").Delete shift:=xlToLeft
'targetSheet.Columns("A:B").Insert shift:=xlToRight, CopyOrigin:=xlFormatFromLeftOrAbove
'targetSheet.Columns("A:B").CurrentRegion.NumberFormat = "#" -> commented this line because cells are going to be empty. What do you want to format as text? maybe this could go after you add the numbers. Also formatting the whole column is a waste of resources
' Insert a number starting at 1 in column A1 (added number 2 to fill down in sequence)
targetSheet.Range("A1").Value = 1
targetSheet.Range("A2").Value = 2
' Sequentially fill in until all rows with records have a number (this doesn't take into account if there are gaps in column b)
Dim referenceRange As Range
Set referenceRange = targetSheet.Range("B1:B" & targetSheet.Range("B" & targetSheet.Rows.Count).End(xlUp).Row)
targetSheet.Range("A1:A2").AutoFill Destination:=referenceRange.Offset(0, -1)
End Sub
Let me know if it works
PS. Check Sidar's answer on how to properly delete empty rows: https://stackoverflow.com/a/9379968/1521579
Could you try this?
'code to enter a sequential number starting at 1 for every row that has a record
'remove your code from here on and substitute with the following
With ActiveSheet
LastRow = .Cells(.Rows.Count, "A").End(xlUp).Row
End With
ActiveSheet.Range("A1").Select
With ActiveCell
.FormulaR1C1 = "1"
.AutoFill Destination:=ActiveCell.Range("A1:A" & LastRow), Type:=xlFillSeries
End With

cannot copy and paste when area size is not the same

Dim lastrow&, lastCol&, myarray As Range
lastrow = Range("A1").End(xlDown).Row
lastCol = Range("XX1").End(xlToLeft).Column
Set myarray = Range("A1").Resize(lastrow, lastCol)
Range("A1", myarray).Select
Selection.Copy
So basically, i am trying to get select an array which could vary, I know it starts at A1, but I'm unsure which row and column it will end at. Code above works fine to help copy this array.
Application.CutCopyMode = False
Selection.Copy
Application.WindowState = xlNormal
Windows("macrofile.xlsm").Activate
Sheets("MRG").Select
'has to find the last row by itself
Range("A" & Rows.Count).End(xlUp).Offset(2, 0).Select
ActiveCell.PasteSpecial (xlPasteAll)
I am getting an error on the last line ActiveCell.PasteSpecial (xlPasteAll).
Error 1004, can't paste because copy area and paste area aren't the same
I have tried different variations including activesheet.paste and xlpastevalues to no avail.
Range("A" & Rows.Count).End(xlUp).Offset(2, 0).Select selects a single cell in column A to find the last used row and offsets it by 2 rows so I can paste below the existing data. Not sure why error 1004 comes up because replicating selecting an array and pasting it into a single cell in excel runs no errors.
Any help is much appreciated; I am really new to VBA and most of this code came from different sources online.
As long as the source data has no blank rows or columns you can do this:
ActiveSheet.Range("A1").Currentregion.Copy _
Workbooks("macrofile.xlsm").Sheets("MRG").Cells(Rows.Count, "A").End(xlUp).Offset(2,0)
Assuming there's room for the pasted data.

Dynamically fill the next empty row with data from another sheet

In advance, I would like to thank anyone who reads this for taking the time to make any suggestions! I have tried other examples I've found on here and none of them seem to work so thanks for any advice!
So essentially I have 3 sheets. In sheet 1, I will be manually entering data into the next empty row (The data spans from Column A to Column U). Sheet 2 is linked to Sheet 1 in a manner to where if I select a row and autofill down to the next one, it will display the data from Sheet 1 (and also increases the values in each cell to account for inflation).
So essentially after I enter data into a new row on Sheet 1, I want to run a macro that will then dynamically autofill the last row on Sheet 2 to the next empty row. I also want this to be repeated going from Sheet 2 to Sheet 3.
An example would be, if Sheet 1 and 2 both have data down to row 35, I want to be able to manually enter data in row 36 and then my macro will autofill row 35 to 36 on Sheet 2.
The code I have written so far is below. To explain, base/basee and home/homee are cells I have named to compare values from specific columns for my if/then statement. I keep getting Error 1004 on the last line where I try and autofill down to the next cell wit Offset(1,0)
Sub PracticeTool()
Dim current1 As Integer
Dim current2 As Integer
Worksheets("City1").Select
Application.Goto Reference:="base"
Selection.End(xlDown).Select
Selection.End(xlDown).Select
current1 = Selection
Worksheets("Inflation").Select
Application.Goto Reference:="basee"
Selection.End(xlDown).Select
Selection.End(xlDown).Select
current2 = Selection
If (current1 <> current2) Then
Application.Goto Reference:="homee"
Selection.End(xlDown).Select
Selection.End(xlDown).Select
Selection.End(xlDown).Select
Range(Selection, Selection.End(xlToRight)).Select
Selection.AutoFill Destination:=Selection.Offset(1, 0), Type:=xlFillDefault
End If
End Sub
Sheet 1 Sample Data: https://i.stack.imgur.com/pTFo5.png
Sheet 2 Sample Data: https://i.stack.imgur.com/kufrV.png
I didnt't get exactly what you wanted to compare, but I think you're close.
This code should solve the requirement.
Read the comments and adjust it to fit your needs.
Public Sub AutoFillSheets()
AutoFillRange "Sheet2", "A", "U"
AutoFillRange "Sheet3", "A", "U"
End Sub
Private Sub AutoFillRange(ByVal targetSheetName As String, ByVal fromColumnLetter As String, toColumnLetter As String)
Dim targetSheet As Worksheet
Dim targetRange As Range
Dim targetLastRow As Long
Set targetSheet = ThisWorkbook.Worksheets(targetSheetName)
' Get the last row in source sheet
targetLastRow = targetSheet.Cells(targetSheet.Rows.Count, 1).End(xlUp).Row
' Set the range to copy
Set targetRange = targetSheet.Range(fromColumnLetter & targetLastRow & ":" & toColumnLetter & targetLastRow)
' You had the error in this line (below). Problem is that to use autofill you need to include the rows from which Excel would calculate the source range (see that I took the last row in the first column, and added one to the second column)
targetRange.AutoFill Destination:=targetSheet.Range(fromColumnLetter & targetLastRow & ":" & toColumnLetter & targetLastRow + 1)
End Sub

VBA Selection.Copy copies a completely different range when running my code

I have spent the day trying to understand what is going on with my excel.. I am running some code which worked fine before, I modified part of it early up (but which still works fine), and now a Selection.Copy later on in the code has stopped working. Here it is :
Range("AE3").Select
Range(Selection, Selection.End(xlDown)).Select
Selection.Copy
I used break points to find the problem. After the first two lines of code, it is the data in column AE which is selected. When I move on to the last line (Selection.Copy), it is not the data in AE which is selected but the columns AA and AB. I have tried literally everything I can think of to try and fix this but can't find anything..
If I run the code up to this point of the code and do the selection and copying manually, it also copies the wrong cells (it copies AA and AB like when it's done with vba)
I would post screenshots of it but you can't put photos here it seems.
Thanks for your help!
Resolved:
I went through the code step by step and noticed that previously in the code I copied the data from columns AA and AB to lower columns. To do so I had selected the columns and then copied them. I changed that so that I selected only the data in the columns and not the columns themselves and copied the data. This change has made my code work. I'm not sure why this was effecting the later Selection.Copy, but it was in some way. Thank you everyone for their help!
As I've suggested in my comment, avoid using .Select & Selection, is usually bad practice and almost everything can be done in VBA without the need to use them. I understand those are a result of the recorder (which is a good place to start learning how to do certain things in VBA), just need to learn as well how to use the code generated by the recorder.
See if this helps (see comments in code as well):
Sub copyRange()
Dim ws As Worksheet
Set ws = ActiveWorkbook.Sheets("Sheet1") 'use a variable for the sheet you want to use
Dim lRow As Long
lRow = ws.Cells(Rows.Count, "AE").End(xlUp).Row 'get the last row at the desired column
With ws
.Range("AE3:AE" & lRow).Copy _
Destination:=.Range("AE3:AE" & lRow).Offset(0, -10) 'destination offset 10 columns to the left
'or alternatively specify the destination
'Destination:=.Range("U3:U" & lRow)
End With
'ALTERNATIVE to the above - copy values only
With ws.Range("AE3:AE" & lRow)
.Offset(0, -10).Value = .Value 'destination offset 10 columns to the left
'or alternatively specify the destination
'ws.Range("U3:U" & lRow).Value = .Value
End With
'2nd ALTERNATIVE to the above - copy values only
With ws.Range(ws.Cells(3, 31), ws.Cells(lRow, 31))
.Offset(0, -10).Value = .Value 'destination offset 10 columns to the left
'or alternatively specify the destination
ws.Range(ws.Cells(3, 21), ws.Cells(lRow, 21)).Value = .Value
End With
End Sub
Note the use of With statement, .Range(...) is not the same as Range(...).
In case you want to copy all in column AE try this:
Range("EA3:EA" & Range("EA" & Rows.Count).End(xlUp).Row)).Copy
And to paste you could use:
Range("U3").PasteSpecial (xlPasteValues)
Also, I strongly suggest you to read:
How to avoid using Select in Excel VBA
You could try:
Option Explicit
Sub test()
Dim LastRow As Long
'Create a with statement refer to the sheet where your data are
With ThisWorkbook.Worksheets("Sheet1")
'Find the LastRow of column AE
LastRow = .Cells(.Rows.Count, "AE").End(xlUp).Row
'Refer to the range starting from AE3 and ends at Lastrow
.Range("AE3" & ":AE" & LastRow).Copy
End With
End Sub
Results:

Excel Macro Repetitive IF and Else

I am currently working on an Excel VBA Macro script where in it will do a simple TRUE or False test to the active cell. My problem is, i cannot make this working until the end of the list. It only run once and ends the program. I need this VB script to perform the IF & ELSE test up to the bottom of the list.
Description of the problem:
Let's say i have a list of dates in A1 to A9999 and beside it (F1:F9999) there's also a list that has a text on it. the F1:F9999 list contains two values only. (a)SAME DATE and (b) NOT THE SAME.
Perform a True or False test in the List F1:F9999.
If the active cell value is equal to the text "SAME DATE" (TRUE), it will ignore and move to the next item in the list then perform again number 1.
If the active cell value is equal to the text "SAME DATE" (FALSE), it will insert a row above it and then move to the next item in the list then perform again number 1
The TRUE or FALSE test will run until the end of the list.
The TRUE or FALSE test will stop running if it reached the bottom of the list.
by the way, the number of items in the list is not consistent. I just put there F1:F9999 for example purposes.
here's my code!
Sub IFandElseTest()
If ActiveCell.Value = "Same Date" Then
Range(Selection, Cells(ActiveCell.Row, 1)).Select
Selection.Insert Shift:=xlDown, CopyOrigin:=xlFormatFromLeftOrAbove
ActiveCell.Offset(1, 0).Select
Else:
ActiveCell.Offset(1, 0).Select
Range(Selection, Cells(ActiveCell.Row, 1)).Select
Selection.Insert Shift:=xlDown, CopyOrigin:=xlFormatFromLeftOrAbove
End If
End Sub
Appreaciate if you could help me on this.
Give this a try.
Explanation:
You should avoid using .Select/ActiveCell etc. You might want to see this LINK
When working with the last row, it's better not to hard code values but dynamically find the last row. You might want to see this LINK
Work with Objects, what if the current sheet is not the sheet with which you want to work with?
The below FOR loop will traverse the row from below and move up.
Code:
Sub Sample()
Dim ws As Worksheet
Dim LRow As Long, i As Long
Dim insertRange As Range
'~~> Chnage this to the relevant sheet
Set ws = ThisWorkbook.Sheets("Sheet1")
'~~> Work with the relevant sheet
With ws
'~~> Get the last row of the desired column
LRow = .Range("E" & .Rows.Count).End(xlUp).Row
'~~> Loop from last row up
For i = LRow To 1 Step -1
'~~> Check for the condition
'~~> UCASE changes to Upper case
'~~> TRIM removes unwanted space from before and after
If UCase(Trim(.Range("E" & i).Value)) = "SAME DATE" Then
'~~> Insert the rows
.Rows(i).Insert Shift:=xlDown, CopyOrigin:=xlFormatFromLeftOrAbove
End If
Next i
End With
End Sub
Screenshot:
Followup From Comments
It really worked! BUT, one final modification. in your code: Set ws = ThisWorkbook.Sheets("Sheet1") Is it possible is you can set the WS as the Active worksheet. The reason of this is because the name of the worksheet unique and not consistent also.
Like I mentioned, in the first link above as well in the comment, do not use Activesheet. Use CodeNames of the sheet which do not change. See the screenshot below.
Blah Blah is the name of the sheet which you see in the worksheet tab but Sheet1 is the CodeName which will not change. i.e. you can change the name of the sheet from Blah Blah to say Kareen but in the VBA editor, you will notice that the Codename doesn't change :)
Change the code
Set ws = ThisWorkbook.Sheets("Sheet1")
to
'~~> Replace Sheet1 with the relevant Code Name
Set ws = [Sheet1]
Edit:
If you leave out the r.copy line it does more or less exactly what Siddharth Rout's solution does
Sub insrow()
Dim v, r As Range
Set r = [d1:e1]
v = r.Columns(1).Value
Do
' r.copy
If v = "Same Date" Then r.Insert Shift:=xlDown, CopyOrigin:=xlFormatFromLeftOrAbove
Set r = r.Offset(1)
v = r.Columns(1).Value
Loop Until v = ""
End Sub
This does not yet include the end condition if row exceeds line 9999 but that should be easy to add ...

Resources