PasteSpecial method of Range class Failed on second run of Macro - excel

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")

Related

Paste Special macro Excel

Sub Copy_Cell2()
'Declare Variables
Dim Wr As Worksheet
'Define the excel sheet
Set Wr = ThisWorkbook.Sheets("Sheet2")
'Code to stop screen updating and flickering ON
Application.ScreenUpdating = False
'Select Sheet1 to get the random value
Sheets("Sheet1").Select
Cells.Select
Range("F1").Select
Range("F1").Copy
'Selects Sheet2 to paste the random value in the next blank cell in column A
Sheets("Sheet2").Select
Range("A2").Select
nrlife = Wr.Cells(Rows.Count, 1).End(xlUp).Offset(1, 0).Select
'Establish what row has been selected
With ActiveCell
vRow = .Row
End With
vRange = "A" & vRow & ""
Range(vRange).Select
'Code to paste value and format from Sheet1 to first empty row on sheet2
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks_:=False, Transpose:=False
'Code to stop screen updating and flickering OFF
Application.ScreenUpdating = True
End Sub
I am getting error in Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks_:=False, Transpose:=False
Error code is Run-time error '1004' Aplication-defined or
object-defined error
Can anyone help me what am i missing?
Your code reduces to:
Dim wb As Workbook
Set wb = ThisWorkbook
wb.Sheets("Sheet2").Cells(Rows.Count, "A").End(xlUp).Offset(1).Value = _
wb.Sheets("Sheet1").Range("F1").Value
You can assign values directly - no need for copy/paste in this case.

VBA Best way to match an ID number from a spreadsheet to another sheet and then update the information

I am doing an Excel Workbook project for a poker room. There is a Player Database within the program. Each player has an ID number.
For the sake of my question I'm going to refer to two Sheets.
When a player comes in for that day they are logged in with Name, ID, and Time (This sheet is Worksheets("Cashout")). Cashout Sheet
Then when the player buys poker chips they get added to another sheet (Worksheets("Tab")).Tab Sheet This sheet keeps track of the chips that are purchased. Some of these players get loans from the house so they end up with a Tab. On the "Tab" sheet there is a cmd button called Cashout.
When the player is done for the day the goal is to click the cashout button and submit any remaining tab and the players end time to the "Cashout" sheet. Since both of these sheets have the players ID number, I am thinking that is how I should find the record on the Cashout page, but let me know if there is an easier way.
I have it working with using do loops and ActiveCell select, but it is a lot of code, and select slows the process. I know there is a better way to do this possibly Find, Match or even a For Each loop. Please let me know to change my code.
I am attaching the code that works, but I don't want to use it.
Private Sub CmdBtnCashout1_Click()
Dim LastRow As Long
Dim Rng1 As Range
Dim Rng2 As Range
Dim Rng3 As Range
Dim ws1 As Worksheet
Dim ws2 As Worksheet
Dim cnt As Integer
Set ws1 = Worksheets("Tab")
Set ws2 = Worksheets("Cashout")
Set Rng1 = Worksheets("Tab").Range("A5")
Set Rng2 = Worksheets("Tab").Range("C4")
Set Rng3 = Worksheets("Tab").Range("W5")
cnt = 1
Application.ScreenUpdating = False
Rng1.Select
Selection.Copy
ws2.Activate
ws2.Range("A4").Select
If ws2.Range("A4") = "" Then
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks:=False, Transpose:=False
ws1.Activate
Rng2.Select
Application.CutCopyMode = False
Selection.Copy
ws2.Activate
ActiveCell.Offset(0, 2).Select
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks:=False, Transpose:=False
ws1.Activate
Rng3.Select
Application.CutCopyMode = False
Selection.Copy
ws2.Activate
ActiveCell.Offset(0, 3).Select
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks:=False, Transpose:=False
ws2.Range("A1").Select
ws1.Activate
ws1.Range("A1").Select
Application.CutCopyMode = False
Range("A1").Select
Else
Do Until ActiveCell.value = ""
ActiveCell.Offset(1, 0).Select
cnt = cnt + 1
If cnt > 49 Then Exit Do
Loop
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks:=False, Transpose:=False
ws1.Activate
Rng2.Select
Application.CutCopyMode = False
Selection.Copy
ws2.Activate
ActiveCell.Offset(0, 2).Select
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks:=False, Transpose:=False
ws1.Activate
Rng3.Select
Application.CutCopyMode = False
Selection.Copy
ws2.Activate
ActiveCell.Offset(0, 3).Select
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks:=False, Transpose:=False
ws2.Range("A1").Select
ws1.Activate
ws1.Range("A1").Select
Application.CutCopyMode = False
Range("A1").Select
End If
Application.ScreenUpdating = True
End Sub
Tab sheet: with Cashout Button: the player name is in Cell A5, ID number is in A4, tab balance is in W5.
Cashout Sheet: player name is within the range of A4:A53 and Player ID number is in range of B4:B53 this is where i would need to match my reference then insert the tab balance from the Tab Sheet in range G4:G53 on the row with that player. I also want to just insert the time stamp in E4:E53.
The sub would be worksheet level sub on the Tab Sheet using the CashoutCommandBtn Click event
How should I do this?
I found a way to do this see the attached code which works perfectly except I have 20 subs for 20 buttons. I know there is a way for me to put the long code into a module and call it from a sub so I am going to try and work on that so that the 20 subs have at least minimal code instead of the long code.
\\
Private Sub CmdBtnCashout1_Click()
Dim Rng2 As Range
Dim TimeOut As Date
Dim wst As Worksheet
Dim wsco As Worksheet
Dim Rng1 As Range
Dim Balance As Range
Dim COPlayer As Range
Dim COPlayerRng As Range
Dim i As Integer
Dim j As Integer
Dim Urng1 As Range
Dim Urng2 As Range
Dim UnionRng As Range
Dim WinLoss As Range
Dim ChipReturn As Range
Set COPlayerRng = Worksheets("Cashout").Range("B4:B53")
Set wst = Worksheets("Tab")
Set wsco = Worksheets("Cashout")
i = 4
j = 5
Set Rng1 = Worksheets("Tab").Cells(i, 1)
Set Rng2 = Worksheets("Tab").Cells(1, 1)
Set Balance = Worksheets("Tab").Cells(j, 23)
Set WinLoss = Worksheets("Tab").Cells(j, 24)
Set COPlayer = COPlayerRng.Find(What:=Rng1.value,LookIn:=xlValues,LookAt:=xlWhole)
Set Urng1 = wst.Range(Cells(i, 1), Cells(j, 1))
Set Urng2 = wst.Range(Cells(i, 3), Cells(j, 22))
Set UnionRng = Union(Urng1, Urng2)
Set ChipReturn = wst.Range(Cells(i, 25), Cells(j, 25))
TimeOut = Time
Application.ScreenUpdating = False
Application.FindFormat.Clear
Application.ReplaceFormat.Clear
With COPlayer
.Offset(0, 7).value = Balance.value
.Offset(0, 3).value = TimeOut
.Offset(0, 6).value = WinLoss.value
End With
Rng2.Select
UnionRng.ClearContents
ChipReturn.ClearContents
wst.Range("A6:V43").Copy
wst.Range("A4").PasteSpecial (xlPasteValues)
Application.CutCopyMode = False
wst.Range("A1").Select
Application.FindFormat.Clear
Application.ReplaceFormat.Clear
Application.ScreenUpdating = True
End Sub
\\
By using a few variables and the "find" function and "with" statement provided me with a solution that works. I am still new to VBA so if there is any way to streamline this code or to use a standard module and calling a sub from there to eliminate the code for 20 buttons let me know. The variables "i" and "j" are used to count rows in the Cells Property. The code above is for one of the buttons on the worksheet. when the command button is pressed the it looks for the matching value for the ID number. After that is complete it takes the data from cell "A4" and "A5 and "C4" and "V5" and moves that information to another worksheet. the variables "i" = 4 and "j" = 5. The next button code is identical except since the row changes "i" = 6 and "J" = 7 and so on.

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

Create a Macro that inserts new data below last entry?

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

Cant write to cell

I am trying to get data from every other sheet in the workbook and paste it into a master sheet (Sheet1), but when I run my code nothing happens, Can someone tell me why this is?
Dim wb As Workbook
Dim ws As Worksheet
Set wb = ActiveWorkbook
wb.Sheets("Sheet1").Cells(1, 1).Text = "Started"
i = 1
'cells is row,col
For Each objWorksheet In wb.Worksheets
'ws.Cells(1, i).Value = objWorksheet.Name
'objWorksheet.Activate
'ws = wb.ActiveSheet
doJStuff i, objWorksheet
i = i + 1
Next
wb.Sheets("Sheet1").Cells(1, 1).Text = "DONE"
End Sub
Sub doJStuff(row, ws)
ws.Select
Range("A2").Select
Application.CutCopyMode = False
Selection.Copy
Sheets("Sheet1").Select
ActiveSheet.Cells(row, 1).Select
ActiveSheet.Paste
'end paste name
'copy post history and transpose into row 2 on sheet1
ws.Select
Range("H2:H30").Select
Application.CutCopyMode = False
Selection.Copy
Sheets("Sheet1").Select
ActiveSheet.Cells(row, 2).Select
Selection.PasteSpecial Paste:=xlPasteAll, Operation:=xlNone, SkipBlanks:= _
False, Transpose:=True
'end post history
End Sub
You've got a number of problems with your code. First of all, avoid using Select wherever possible. Second, you are not properly assigning variables. You should put Option Explicit on the top of the module and then make sure you've assigned things correctly.
As for the actualy code, when you are copying/pasting the H2:H30 range into your first sheet you are going to only end up getting the first value in the range for every sheet except the last because you are pasting 28 rows but only incrementing the destination row by one. I didn't fix that but it's worth pointing out. I also left in your comments though they don't make much sense. Without knowing what you are trying to do, I've only cleaned up some of your code but it probably still won't work exactly right.
Sub YourSub()
Dim wb As Workbook
Dim wksht As Worksheet
Dim i As Integer
Set wb = ActiveWorkbook
wb.Sheets("Sheet1").Cells(1, 1).Text = "Started"
i = 1
'cells is row,col
For Each wksht In Worksheets
'ws.Cells(1, i).Value = objWorksheet.Name
'objWorksheet.Activate
'ws = wb.ActiveSheet
doJStuff i, wksht
i = i + 1
Next
wb.Sheets("Sheet1").Cells(1, 1).Text = "DONE"
End Sub
Sub doJStuff(row As Integer, ws As Worksheet)
ws.Range("A2").Copy
Sheets("Sheet1").Cells(row, 1).PasteSpecial
'end paste name
'copy post history and transpose into row 2 on sheet1
ws.Range("H2:H30").Copy
Sheets("Sheet1").Cells(row, 2).PasteSpecial Paste:=xlPasteAll, Operation:=xlNone, SkipBlanks:= _
False, Transpose:=True
'end post history
End Sub

Resources