Create a Macro that inserts new data below last entry? - excel

I am new to the VBA and Macro world. I am trying to create a data collection sheet. First part data is collected in from 1 workbook and placed in workbook master. What I would like to achieve is the new data that I extract will be placed below the previous entry in the workbook master.
Sub Extract() ' ' Extract Macro ' ' Keyboard Shortcut: Ctrl+e '
Sheets("For Coordinator Use").Select
Range("A2:M41").Select
Selection.Copy
Windows("Nimble Schedule Import Template- ops.xlsx").Activate
Range("A1000").End(xlUp).Select
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=False
ActiveSheet.ListObjects("Table1").Range.AutoFilter Field:=1, Criteria1:= _
"=0", Operator:=xlOr, Criteria2:="="
Application.CutCopyMode = False
Selection.EntireRow.Delete
ActiveSheet.ListObjects("Table1").Range.AutoFilter Field:=1
Windows("Coverage Request Form (9).xlsx").Activate
Sheets("Request Form").Select
End Sub

Here is a modified and commented copy of your code:
Sub Extract() ' ' Extract Macro ' ' Keyboard Shortcut: Ctrl+e '
Sheets("For Coordinator Use").Select
Range("A2:M41").Copy 'No need to select then copy, just copy is fine
Windows("Nimble Schedule Import Template- ops.xlsx").Activate
'I have offset the last row of data by 1 row below, use rows.count rather than a hard row number. Also no need to select
Range("A" & Rows.Count).End(xlUp).Offset(1, 0).PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks:=False, Transpose:=False
ActiveSheet.ListObjects("Table1").Range.AutoFilter Field:=1, Criteria1:="=0", Operator:=xlOr, Criteria2:="="
'I don't know what row is selected here but it was in your code so I left it, also no need for cutcopymode as it will cancel when you delete anyway
Selection.EntireRow.Delete
ActiveSheet.ListObjects("Table1").Range.AutoFilter Field:=1
Windows("Coverage Request Form (9).xlsx").Activate
Sheets("Request Form").Select
End Sub
Please read the comments and ask any questions about it where you are unsure. These changes are because you have stipulated you are new to this and I don't want to confuse you, this is NOT the best way to do it, I would much rather set up something with arrays than a copy and paste. If you are comfortable with this concept post back and I will modify my code for you.

It depends how you would like to do it. Do you want to maybe use an array to store the data in then extract to the master spreadsheet or do you want to just use excels built in functions to copy and paste the data like you are doing above. You could also use a scripting dictionary to store the data as well there are many ways to do it just wondering which route you want to take. If you want to have a high performance macro then I suggest not to use excel's built in functions as they are slower than using arrays.
Update 2015-08-20
I have got the copy and paste using the range object. However I see you want to delete some other values from your list although they are kept in a table and not in a spreadsheet. Is this correct? Please have a look at the code I made some comments asking for some clarifications. Sorry for taking so long I was busy finishing something up at work.
Sub Extract() ' ' Extract Macro ' ' Keyboard Shortcut: Ctrl+e '
Dim wb As Workbook, ws As Worksheet, rng As Range
Set wb = ThisWorkbook 'Set up the Excel objects you want to use
Set ws = wb.Worksheets("For Coordinator Use")
Set rng = ws.Range("A2:M41") 'asuming this is not changing
'Sheets("For Coordinator Use").Select 'You do not need to select if you use the objects
'Range("A2:M41").Select 'You do not need to select if you use the objects
'Selection.Copy 'you can also get rid of this if using objects
Dim wbDest As Workbook, wsDest As Worksheet, rngDest As Range
Set wbDest = Application.Workbooks("Nimble Schedule Import Template- ops.xlsx") ' Assuming that it is opened
'Windows("Nimble Schedule Import Template- ops.xlsx").Activate 'dont need to activate anything
Set wsDest = wbDest.Worksheets("Sheet1")
Set rngDest = wsDest.Range("A1:A35000")
''optimize the application
Application.ScreenUpdating = False
Application.Calculation = xlCalculationManual
Application.EnableEvents = False
''''
'''Find the first empty cell in destRng
'Range("A1000").End(xlUp).Select ' this will select the range that is blank only if it does not have data to begin with
Dim i As Long, j As Long, rngAdd As String 'i is the counter and j stores the row where it is blank
For i = 1 To rngDest.Cells.Count
If IsEmpty(rngDest.Cells(i, 1).Value) Then
j = i
i = rngDest.Cells.Count
End If
Next i
'reset the rngDest
Set rngDest = Nothing
rngAdd = "A" & j & ":M" & (j + 39)
Set rngDest = wsDest.Range(rngAdd)
'make rngDest = rng.Value since they have the same dimension this works
rngDest = rng.Value 'Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
' :=False, Transpose:=False
'I am not sure what you are trying to acheive here a filter??'ActiveSheet.ListObjects("Table1").Range.AutoFilter Field:=1, Criteria1:= _
' "=0", Operator:=xlOr, Criteria2:="="
'Application.CutCopyMode = False
'Selection.EntireRow.Delete
'ActiveSheet.ListObjects("Table1").Range.AutoFilter Field:=1
''Looks like you are deleting all with a value of "=0"
'Windows("Coverage Request Form (9).xlsx").Activate
'Sheets("Request Form").Select
'Release Objects
Set rngDest = Nothing
Set wsDest = Nothing
Set wbDest = Nothing
Set rng = Nothing
Set ws = Nothing
Set wb = Nothing
''set excel optimization as normal again
Application.ScreenUpdating = True
Application.Calculation = xlCalculationAuto
Application.EnableEvents = True
End Sub

Related

Using VBA with Tables

I am trying to create a simple insert row to 'table', 'copy' second row and 'paste' into first row. Currently I have just created the below as it was logical to me and I cannot find any reference on the internet so far.The table has another table above it so the cell are constantly shuffling down and have no point of reference aside from the table itself.
It inserts a row but does not copy and paste the values, Formulas, and formatting (data validated droplist) from second row. I also want to clear the contents of the first and fifth column in the first row. there are no error messages.
Sub AddPkgBeer()
'
' AddPkgBeer Macro
'
'
Sheets("BEER MENU").Select
ActiveSheet.Unprotect Password:="password"
Range("Table36356").Select
Selection.ListObject.ListRows.Add (1)
ActiveSheet.ListObjects("Table36356").DataBodyRange(2).Select
Selection.Copy
ActiveSheet.ListObjects("Table36356").DataBodyRange(1).Select
Selection.PasteSpecial Paste:=xlPasteFormulasAndNumberFormats, Operation:= _
xlNone, SkipBlanks:=False, Transpose:=False
Application.CutCopyMode = False
ActiveSheet.ListObjects("Table36356").DataBodyRange(1, 1).Select
Sheets("BEER MENU").Select
ActiveSheet.Protect Password:="password"
End Sub
Sub AddPkgBeer()
Dim ws As Worksheet, rng As Range, tbl As ListObject
Set ws = ActiveSheet
Set tbl = ws.Range("Table36356").ListObject
tbl.ListRows.Add 1
Set rng = tbl.ListRows(1).Range
tbl.ListRows(2).Range.Copy rng
rng.Cells(1, 1) = ""
rng.Cells(1, 5) = ""
End Sub

Search for next empty cell

I want to copy data in certain cells to another sheet in a table.
My code copies the data and searches for the cell to be pasted to. If there is a value in the destination cell, it is looped to check the subsequent rows in the same column until it finds an empty cell.
If there's 2000 rows of data currently in the table, it will search all 2000 cells before landing in the 2001st row.
The amount of time taken to execute the code is affected by the size of the table.
Is there any way to execute faster?
Below is a sample, its copying data from two cells.
Sub Test()
Sheets("Sheet1").Select
Range("K10").Select
Selection.Copy
Sheets("Table").Select
Range("A2").Select
Do While Not (ActiveCell.Value = "")
ActiveCell.Offset(1, 0).Activate
Loop
Selection.PasteSpecial Paste:=xlValues, Operation:=xlNone, SkipBlanks:= _
False, Transpose:=False
Sheets("Sheet1").Select
Range("G15").Select
Selection.Copy
Sheets("Table").Select
Range("B2").Select
Do While Not (ActiveCell.Value = "")
ActiveCell.Offset(1, 0).Activate
Loop
End sub
Try following sub.
Sub CopyPaste()
Dim sht1, sht2 As Worksheet
Set sht1 = Worksheets("Sheet1")
Set sht2 = Worksheets("Table")
sht1.Range("K10").Copy sht2.Cells(Rows.Count, 1).End(xlUp).Offset(1, 0)
sht1.Range("G15").Copy sht2.Cells(Rows.Count, 2).End(xlUp).Offset(1, 0)
End Sub
It's unclear on whether you expect to find interim blank cells within the worksheet's used range or whether you expect to always put the new values at the bottom of the used range. This should work for both scenarios.
Sub Test()
Dim ws1 As Worksheet
Set ws1 = Worksheets("sheet1")
With Worksheets("table")
'force a definition for a .UsedRange on the worksheet
.Cells(.Rows.Count, "A") = Chr(32)
.Columns(1).SpecialCells(xlCellTypeBlanks).Cells(1) = ws1.Cells(10, "K").Value
.Columns(1).SpecialCells(xlCellTypeBlanks).Cells(1) = ws1.Cells(15, "G").Value
'clear the artificial .UsedRange
.Cells(.Rows.Count, "A").Clear
'Debug.Print .UsedRange.Address(0, 0)
End With
End Sub

PasteSpecial method of Range class Failed on second run of Macro

First off I am not a coder. I am trying to get a section of this code to increment the column number each time the macro is run. It works the first time then has the Range class error the next run. Also my incrementing doesn't appear to be working either. Here is the complete code with the section giving the error pointed out:
Sub Prep_Report_Rev_B()
'
' Prep_Report_Rev_B Macro
'
' Keyboard Shortcut: Ctrl+g
'
' Declare Variables
Dim xdate As Date
Dim incCol As Integer
' Ensure button not pressed multiple times a day
xdate = Worksheets("Summary").Range("F6")
If Month(Date) = Month(xdate) And Year(Date) = Year(xdate) And Day(Date) = Day(xdate) Then
MsgBox "Report can only be run once per day to prevent data loss"
GoTo Line1
End If
' Copy Data to Historical Tab
' ** Need to increment column number **
If incCol = 0 Then
incCol = 1
Else
incCol = incCol + 1 '<--increases of 1 each click
End If
ActiveSheet.Unprotect "0000"
Range("L3:L8,L11:L15,L18:L22,L34:L38,L41:L45,L57:L61,L64:L68").Select
Selection.Copy
Sheets("Historical Data").Select
ActiveSheet.Unprotect "0000"
' =========================================================================
Cells(2, incCol).Offset(0, 5).Select
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=True, Transpose:=False ' <----
' ==========================================================================
ActiveSheet.Protect "0000"
' Enter current Date on "Summary" Page
Sheets("Summary").Select
Range("F6") = Format(Date, "mm/dd/yyyy")
ActiveSheet.Protect "0000"
' Clear "Previous Service Report Data" tab
Sheets("Previous Service Report Data").Select
ActiveSheet.Unprotect "0000"
Cells.Select
Selection.ClearContents
' Copy data from "Service Report" to "Previous Service Report"
Sheets("Service Report Data").Select
ActiveSheet.Unprotect "0000"
Columns("A:AK").Select
Selection.Copy
Sheets("Previous Service Report Data").Select
Range("A1").Select
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=False
ActiveSheet.Protect "0000"
' Clear "Service Report Data" to prepare for new data
Sheets("Service Report Data").Select
Columns("A:AI").Select
Selection.ClearContents
Range("A1").Select
ActiveSheet.Protect "0000"
' Pull Up webpage
ActiveWorkbook.FollowHyperlink _
Address:="google.com"
Line1:
End Sub
Any help or suggestions would be greatly appreciated.
Here try this, it will move the selected range into a new range. This code should select your range and move it to the Historical Data Sheet. Make sure to change the name on set sh = wb.Sheets("NAME OF YOUR SHEET") to the name of your sheet. I would probably create a test sheet for both to test them to make sure they are doing what you want them to do and you don't mess up your data.
Dim sh As worksheet
Dim sh1 As worksheet
Dim rng, rng1, rng2, rng3, rng4, rng5, rng6 As range
set wb = ThisWorkbook
set sh = wb.Sheets("NAME OF YOUR SHEET")
set sh1 = wb.Sheets("NAME OF SHEET YOU WANT TO COPY TO")
set rng = sh.Range("L3:L8")
set rng1 = sh.Range("L11:L15")
set rng2 = sh.Range("L18:L22")
set rng3 = sh.Range("L34:L38")
set rng4 = sh.Range("L41:L45")
set rng5 = sh.range("L57:L61")
set rng6 = sh.range("L64:L68")
sh1.Range("A1").Resize(rng.Rows.Count, rng.Columns.Count).Cells.Value = rng.Cells.Value
sh1.range("B1").Resize(rng1.Rows.Count, rng1.Columns.Count).Cells.Value = rng1.Cells.Value
sh1.range("C1").Resize(rng2.Rows.Count, rng2.Columns.Count).Cells.Value = rng2.Cells.Value
sh1.range("D1").Resize(rng3.Rows.Count, rng3.Columns.Count).Cells.Value = rng3.Cells.Value
sh1.range("E1").Resize(rng4.Rows.Count, rng4.Columns.Count).Cells.Value = rng4.Cells.Value
sh1.range("F1").Resize(rng5.Rows.Count, rng5.Columns.Count).Cells.Value = rng5.Cells.Value
sh1.range("G1").Resize(rng6.Rows.Count, rng6.Columns.Count).Cells.Value = rng6.Cells.Value
Edit - I kind of spelled it out for you in hope if you need to make changes its easy to see what the code is doing, there is probably a better way to do this with less code but this way you are not using copy and paste it just transfers the data and is much faster. I set each range to the first row in each column. To change where you the data is placed just change the location after the sh1.range("G1")

Deleting Blank Rows

I have the following macro which has worked great for copy and paste, then the person working with the workbook goes to the newly created sheet and starts deleting rows not necessary to the end product. I have tried adding a line to have the macro delete blank rows, but it is not working. I think possibly because it is not on the active sheet? If I could get the macro to delete blank rows in the range I have added to the macro then I can build from there; as we have many ranges to look through and delete from. I am still learning about macros so any education you could give me would be much appreciated.
Here is the macro I have. It is the 'Delete lines from new sheet that is not working.
Sub CopyandPaste()
'Copy and Paste to Worksheets
'
'Select from MASTER sheet
Range("A1:H1500").Select
Selection.Copy
' Add new sheet for each Tech
Sheets.Add After:=Sheets(Sheets.Count)
Selection.PasteSpecial Paste:=xlPasteColumnWidths, Operation:=xlNone _
, SkipBlanks:=False, Transpose:=False
ActiveSheet.Paste
'Copy again to paste values
Range("A1:H1500").Select
Selection.Copy
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=False
Application.CutCopyMode = False
'Name new sheet Tech's name
Sheets(Sheets.Count).Select
Sheets(Sheets.Count).Name = Sheets(Sheets.Count).Range("a2").Value
'Delete blank lines from new sheet
ActiveSheet.Range("F282:F834").SpecialCells(xlCellTypeBlanks).EntireRow.Delete
End Sub
The routine below is how I might tackle this task. Comments are included to help explain what's going on:
Option Explicit
Sub CopyAndPasteRev2()
Dim Source As Range, Dest As Range, Remove As Range
Dim Master As Worksheet, Target As Worksheet
'set references up-front, assuming you
'start with the MASTER sheet active
Set Master = ThisWorkbook.ActiveSheet
Set Source = Master.Range("A1:H1500")
Set Target = ThisWorkbook.Sheets.Add
Set Dest = Target.Range("A1")
'copy range from master to target
Source.Copy Destination:=Dest
'copy the column width formatting from master to target
Source.Copy
Dest.PasteSpecial (xlPasteColumnWidths)
'remove rows that are blank in col F using
'autofilter to look for empty cells
Dest.AutoFilter
With Target.AutoFilter.Range
.AutoFilter Field:=6, Criteria1:=vbNullString
Set Remove = .Offset(1).Resize(.Rows.Count - 1).SpecialCells(xlCellTypeVisible)
Remove.Delete Shift:=xlUp
End With
'clear filters safely
With Target
.AutoFilterMode = False
If .FilterMode = True Then
.ShowAllData
End If
End With
'move target sheet to be the last one in the workbook
Target.Move After:=ThisWorkbook.Worksheets(Sheets.Count)
End Sub
In most case runtime exception are caused by the Select and ActiveSheet methods.
You need to use them less as possible and use Range and Worksheet variables instead :
Sub CopyandPaste()
'Copy and Paste to Worksheets
'
'Select from MASTER sheet
Dim MasterSheet As Worksheet
Set MasterSheet = Sheets("Master")
MasterSheet.Range("A1:H1500").Copy
Dim newSheet As Worksheet
' Add new sheet for each Tech
Set newSheet = Sheets.Add(After:=Sheets(Sheets.Count))
newSheet.Range("A1").PasteSpecial Paste:=xlPasteColumnWidths, Operation:=xlNone _
, SkipBlanks:=False, Transpose:=False
newSheet.Range("A1").PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=False
'Copy again to paste values
Application.CutCopyMode = False
'Name new sheet Tech's name
On Error Resume Next
Sheets.Item(newSheet.Range("a2").Value).Delete
On Error GoTo 0
newSheet.Name = newSheet.Range("a2").Value
'Delete blank lines from new sheet
For i = 834 To 282 Step -1
With newSheet.Cells(i, "F")
If .Text = "" Then .EntireRow.Delete
End With
Next i
End Sub

Need to add paste special condition a copy.destination for loop

I have a range of data that is in the same position in every worksheet in a book and will always be in that position. When the macro is run the data should be copied and added to a report sheet. I have that part working but I need to use a paste special:
.PasteSpecial xlPasteValues
as there are formulas in the range. I am unsure where to add the paste special condition in this code, since I'm using .Copy, Destination.
Option Explicit
Sub CreateTempPSDReport()
Dim WS As Worksheet, Rept As Worksheet
Set Rept = Sheets("Temporary PSD Report")
Application.ScreenUpdating = False
'--> Loop through each worksheet except the report and
'--> Copy the set range to the report
For Each WS In ThisWorkbook.Worksheets
If Not WS.Name = "Temporary PSD Report" Then
WS.Range("A42", "I42").Rows.Copy _
Destination:=Rept.Cells(Rows.Count, "A").End(xlUp).Offset(1, 0)
End If
Next
Application.ScreenUpdating = True
End Sub
I need to use a paste special:
WS.Range("A42", "I42").Rows.Copy _
Destination:=Rept.Cells(Rows.Count, "A").End(xlUp).Offset(1, 0)
In such a case you do not use the above method. You use this
WS.Range("A42", "I42").Rows.Copy
Rept.Cells(Rows.Count, "A").End(xlUp).Offset(1, 0).PasteSpecial _
Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks:=False, Transpose:=False

Resources