How to speed up copying cells in Excel vba - vba

I have this Excel VB code, and everytime after it executes this line, it pauses for half a second:
Worksheets(ws.Name).Range("A" & i & ":G" & i).Copy _
Destination:=Worksheets("Sheet1").Range("A" & emptyCell)
Can someone tell me what it is doing, and how I can prevent it from taking so long?
I have Microsoft Excel 2007 on Windows XP Pro
Update: If I paste it by hand, it waits about the same amount of time.

It all depends on the specs of the hardware (hard drive, memory, network connection, ect). If its running on a network, that will be the biggest bottleneck. There is nothing inherently wrong with the code.
You can also try speeding up the routine by turning the workbooks calculation to manual, and turning off screen updating. If the calculation is automatic it will calculate on every copy call.

It's copying a range of cells from the worksheet assigned to the variable ws and pasting it to Sheet1.
The range it is copying is from A:G in the row number assigned to the variable i.
It is pasting the range into column A in Sheet1 in the row number assigned to the variable emptyCell.
You can prevent it by prefixing each line with an apostrophe.
However, you may first wish to explore WHY the code is doing that!

Related

excel to access selective row transfer instead of the whole spreadsheet

I have experience with Excel but not much with access. I am trying to create a "Database" where bunch of similar data from many workbooks is kept together in one file in MS-Access.
All the workbooks are made up of many worksheets, but all of them include a "Data" worksheet which data gets inserted into with macros from all the other worksheets in the same workbook.
This data sheet is the same for all the workbooks, made up of headers starting in cell A1 and all the way to BL1. Data gets inserted starting with A3 (so A3 to BL3). Data is inserted with a macro as a whole row(A3-BL3 all together).
CURRENTLY:
The code I am currently using is below, which transfers the whole worksheet set up on a timer(every 12 hours), but I am trying to find a better solution to achieve my goal.
PROBLEMS CURRENTLY:
1) It is too slow, I have over 10,000 rows of data, and trasnferring the whole worksheet every 12 hours is not the fastest or best method (I really dont like doing it this way).
2) Excel workbook is always open and in use, so when timer kicks in and it is running the Excel-to-Access Macro this could cause confusion to the user and/or crash(I do not even want the user to be aware of this access database)
GOAL:
Have this macro run from Excel, every time new data row is created in the Data worksheet(A6-BL6), and have it inserted into the access database table without deleting anything else(basically inserting into access 1 row every time new row of data is created in the Data worksheet in excel. I want it to push old data down in access so everything is kept and nothing is overwritten or lost.
It is crucial I run the macro from excel and not access(dont even want access to be accessible or opened by other user just want data stored there)
Excel and Access are both 2016.
If anyone could please help and/or give me suggestions I would appreciate it, have done some research but haven't found anything that solved my problem completely.
Option Explicit
Sub AccImport()
Application.OnTime Now + TimeValue("12:00"), "AccImport"
Dim acc As New Access.Application
acc.OpenCurrentDatabase "C:\Users\yilly1\Desktop\Database.accdb"
acc.DoCmd.TransferSpreadsheet _
TransferType:=acImport, _
SpreadSheetType:=acSpreadsheetTypeExcel12Xml, _
TableName:="Workbook1", _
Filename:=Application.ActiveWorkbook.FullName, _
HasFieldNames:=True, _
Range:="Data1$A1:BL60000"
acc.CloseCurrentDatabase
acc.Quit
Set acc = Nothing
End Sub

Excel VBA "Overflow" Error on setting Range.Value

I have a macro that runs when the Excel workbook is opened, and basically takes data from a tab named "current day" and moves it to "previous day" and then takes data from another workbook and pastes it into current day(actually uses range.value not copy/paste). Everything was working fine for multiple tests over several days. However, now it is throwing an Overflow Error on the Range.Value part of the code. This is definitely not a size issue as the code is:
PrevDay.Range("A1:Q" & ScoreCurRows).Value = CurrDay.Range("A1:Q" & ScoreCurRows).Value
Where ScoreCurRows is declared as a Long and pulls the UsedRange from the "Current Day" sheet and PrevDay is defined as Sheets("Previous Day") and CurrDay is defined as Sheets("Current Day"). It also is usually under 20 rows worth of data, so even if it was an integer, this still shouldn't cause a problem.
Does anyone have an idea why this is suddenly throwing an Overflow Error and if there is something I should be looking for?
You must have some values in the source range that caused the overflow when VBA tried to load them into a variant array in
= CurrDay.Range("A1:Q" & ScoreCurRows).Value
For example, a cell formatted as date with a value that's too large for a date. For this reason, use .Value2 instead, which will return the dates as normal numbers without trying to convert them.Besides, although most posts on SO donmt stick to this rule, it is known good practice to always use .Value2 when reading a range value (not necessarily when assigning).
PrevDay.Range("A1:Q" & ScoreCurRows).Value = CurrDay.Range("A1:Q" & ScoreCurRows).Value2
' ^^^^^^

Using Excel Macro to truncate in specified cells but still allow data entry in the same cell

I am completely new at working with Excel Macro but have encountered a spreadsheet issue at work that I believe may be solved by using a Macro formula. I need to truncate a value (cannot be rounded) to the second decimal place in specified cells. However, the values to be truncated must be entered by a third party using a template spreadsheet that the Macro formula will be attached to. Is there a way to lock a formula to certain cells while allowing data entry in those cells that would be updated by the formula? I have used the Macro below to successfully truncate cell values and now just need a way to force that Macro to run every time new data is input into the specified cells.
Sub TruncateSelection()
ActiveSheet.Range("A1:A15").Select
Dim Cell As Range
With Selection.Cells
.Value = Evaluate("IF(ROW(1:" & Selection.Cells.Count & "),TRUNC(" & .Address & ",2))")
End With
End Sub
You will need to bind your script to the Worksheet_Change event in VBA
This MSDN article should shed some light on what you'll need to do.
https://msdn.microsoft.com/en-us/library/office/ff839775.aspx

Excel 2013 upgrade "broke" my VBA function

The attached code is meant as a table of contents builder. Depending on what row the function is on, it plucks certain cells from subsequent worksheets.
Asset Location Model
__________________________________________________________
Freezer Kitchen Freezerator 5000 (from worksheet 2)
Television Den Panasung 55" (from worksheet 3, etc.)
Before the "upgrade", the function just worked. Now, it works if I edit sells, but if I copy cells within the same worksheet (anywhere, not just the "special" cells), the cells flicker and flicker for many seconds and then resolve. Sometimes it fails with an overflow error (if I recall correctly, it didn't do it today.) Copying cells from one worksheet to another just works with no such delay.
If I comment out the Application.Volatile line, the delays go away, but the function does nothing.
Code:
'Return values in subsequent worksheets based on row that the function
'is located on. Usage in this particular instance is a TOC
'Num = number of rows to offset, based on starting position of the TOC
'and skipping any worksheets not to be included in the TOC
'srow and scol is the target cell on the following worksheets
Function GetSpot(num, srow, scol)
Application.Volatile
If num > (ThisWorkbook.Worksheets.Count) Then
GetSpot = " "
Else
GetSpot = ThisWorkbook.Worksheets(num).Cells(srow, scol).Value
End If
If GetSpot = 0 Then GetSpot = " "
End Function
Any ideas?
Thanks in advance.
The issue you're experiencing is a bug in Office 2013 related to user-defined function use within a worksheet. We reported this to Microsoft and were told it will not be made part of a hotfix release as only 3 other people have reported it.
When you have a user-defined function within your worksheet and you perform an action such as copy/paste or insert rows, the worksheet takes painstakingly long to complete calculation. This occurs anytime you have a selection where there are marching ants (for lack of a better term) around the selection and the worksheet with user-defined functions calculates.
It's not your function, it's Office 2013. Here's a quick way to replicate the issue:
Create a new blank workbook
Open Visual Basic Editor and add a new Module
Paste the following VBA in the module
Function TimesTwo(ver)
TimesTwo = ver * 2
End Function
On the workbook, paste the formula =INT(RAND()*8) into cell A1
In the range D1:F100, paste the formula =TimesTwo($A$1)
After configuring the workbook like the above, perform a copy and paste within that worksheet.
The result is that the calculation will take a very long time to complete, which can be seen in the status bar.
There are no workarounds aside from using native Excel functions, if available or working with the Workbook Calculation set to Manual. That is, disabling calculation of the worksheet until you manually invoke it.

Macro to copy and change set numbers Excel

so am working on a spreadsheet to simplify logging of data. However it's quite a tedious process of copy, paste & change. Is there a way I can create a Macro to copy the following:
=IF(Trade2!I16=99,0,Trade2!I15)
Paste it the cell directly below but as
=IF(Trade3!I16=99,0,Trade3!I15)
Beyond this it needs to be copied 100 times. Am at 15 typing it manually each time and losing the will to live haha
This seems insanely simple but everything am trying is leading to a massive mess, am good at getting the spreadsheet side working but the coding isn't my strong point.
Any advice would be greatly appreciated
If you use this formula:
=IF(INDIRECT("Trade"&ROWS(A$1:A1)&"!I16")=99,0,INDIRECT("Trade"&ROWS(A$1:A1)&"!I15"))
this returns:
=IF(Trade1!I16=99,0,Trade1!I15)
But you can now copy it down, and the sheet number increases.
The ROWS formula functions as a counter as you copy it down. The INDIRECT formula returns a reference to a sheet.
not sure what you mean but try this
Sub Main()
Dim i As Long
For i = 1 To 10000
Range("A" & i).Formula = "=IF(Trade2!I" & i + 1 & "=99, 0, Trade2!I" & i & ")"
Next i
End Sub