VBA : wrong formula - freezing and not enough memory message - vba

I have a code on VBA that makes my Excel freezing (filling cells) and gives a output message like "not enough memory to run" + error 1004, but I don't understand why because it's really a simple formula.. There's only one part of the full code that causes the issue and here is it:
Sub mismatches()
Dim sht As Worksheet, cell As Range, areaToTrim As Range, LastRow As Long
LastRow = Cells(Rows.Count, "A").End(xlUp).Row
Set sht = ThisWorkbook.Worksheets("Mismatches")
sht.Activate
Range("O1").EntireColumn.Insert
sht.Cells(1, 15) = "Mismatch DRP"
Range("02:0" & LastRow).Value = _
"=IF(ISNA(VLOOKUP(K2,CDL_data!D:D,1,0)),""N/A"",I2)"
Range("02:0" & LastRow).Select
Selection.Copy
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone,
SkipBlanks:=False, Transpose:=False
I'd like to precise that the other parts of the code are almost exactly the same, only the formula is different, but they run properly! Something has to be "wrong" or "too heavy" in the formula, even if I've already used this kind of formula. I've tried the full code with only 3 rows (on sheet "Mismatches") but there are 9000 rows in the sheet "CDL_data" (used for the Vlookup).

You probably have a typo, using zero instead of the letter O in the column reference. This means that you are referencing a number of whole rows, probably 9000 of them and inserting a Vlookup function into 16384 cells per row, which is roughly 147 Million cells that will need to calculate the Vlookup.
You probably want to change this part of the code from using a zero
Range("02:0" & LastRow).Value = _
"=IF(ISNA(VLOOKUP(K2,CDL_data!D:D,1,0)),""N/A"",I2)"
Range("02:0" & LastRow).Select
to this, using the letter O as the column reference:
Range("O2:O" & LastRow).Value = _
"=IF(ISNA(VLOOKUP(K2,CDL_data!D:D,1,0)),""N/A"",I2)"
Range("O2:O" & LastRow).Select
You may want to change your VBE font to something that uses a distinctly different character for Zero as compared to uppercase O, to avoid such mistakes. Consolas uses a diagonal strike on a zero, which makes it very easy to distinguish it from an O.
In general, if you want your code to run faster, avoid selecting things and then acting on selections. In most cases it is possible to act on the range directly.

Related

VBA not updating Excel rows referring to other sheets in same workbook when sorting rows alphabetically

I'm having problems, Excel is not updating rows referring to other sheets in same workbook when ordering rows alphabetically.
I have a userform in which there's a button insertCM with this code:
Private Sub insertButton_Click()
ActiveCell.EntireRow.Select
Selection.Insert Shift:=xltoDown
Range("A9:AK9").Copy
Range("A8:AK8").Select
Selection.PasteSpecial Paste:=xlPasteFormulas
Selection.PasteSpecial Paste:=xlPasteFormats
Range("C10").Copy
Range("C8:C9").Select
Selection.PasteSpecial Paste:=xlPasteFormulas
Range("H9:AK9").Copy
Range("H8:AK8").Select
Selection.PasteSpecial Paste:=xlPasteAll
nomCM = Empty
CXinitial = Empty
resteCX = Empty
CCselect = Empty
C4initial = Empty
resteC4 = Empty
compteurCT = Empty
Range("A8").Activate
ActiveCell.RowHeight = 18.6
For i = 2 To ThisWorkbook.Sheets.Count
With Sheets(i).Select
emptyRow = Range("A9").End(xlDown).Offset(0, 2).Row
Range("A9:AL" & emptyRow).Sort _
Key1:=Range("A9"), Order1:=xlAscending
Set SearchRange = Range("A8", Range("A200").End(xlUp))
Set FindRow = SearchRange.Find(nomCM, LookIn:=xlValues, LookAt:=xlWhole)
Range("A" & FindRow.Row).Select
ActiveCell.EntireRow.Activate
End With
Next i
Sheet2.Select
End
End Sub
The userform is used for inserting new clients in several sheets at the same time. Textbox inserts Name, Cost Center, etc., in a blank row and insertButton inserts a new row leaving data inserted in row 8 to go to row 9. After that the code puts all rows alphabetical order so the new client now in row 9 goes to the new one, and cells containing formulas change row numbers.
However some of the sheets have cells containing references to other sheets' cells in the same row. So imagine:
I insert client name "LORUM" "Cost Center 4" and it puts him in row 9 so formula is:
=$C9-COUNTIF($E9:$P9;"CT")+'Sheet5'!$D9
...but when it changes his row to the final one, formula row is:
=$C18-COUNTIF($E18:$P18;"CT")+'Sheet5'!$D9
It does not change row when referring to other sheets.
Any ideas?
It's looks like you've made a good effort, but there are still numerous problems with your code (beside the one line), and I can guarantee that a combination of these issues are preventing your intended outcome.
I can't fix it completely because there are so many bugs that I'm not clear on what you're trying to do, but hopefully this will get you started on the right track...
xlToDown is not a valid reference. You probably mean xlDown
you have a number of undeclared variables and objects, like: i, emptyRow, SearchRange, FindRow, nomCM
you have things (objects?) "set to nothing" that aren't declared or used anywhere: CXinitial, resteCX, CCselect, C4initial, resteC4, compteurCT
your Find statement is looking for nomCM which is empty (and never set), so the Find statement will never find anything.
You should put Option Explicit at the top of every module (especially when learning or troubleshooting). This will prevent issues like the ones above by "forcing" you to properly declare & handle all of your variables, objects, properties, etc.
Near the end, you refer to Sheet2.Select as if Sheet2 is a declared object, instead of using Sheets("Sheet2").Select. I'm not sure why you're selecting the sheet at the very end anyhow.
You have an With..End statement that is doing absolutely nothing since you don't reference it with a . dot anywhere: With Sheets(i).Select .. End With, and also Select isn't used like that.
A mystery End near the end for some reason.
Also, you're unnecessarily doubling up commands like:
ActiveCell.EntireRow.Select
Selection.Insert Shift:=xlDown
..instead of:
ActiveCell.EntireRow.Insert Shift:=xlDown
and another example, all this:
Range("A9:AK9").Copy
Range("A8:AK8").Select
Selection.PasteSpecial Paste:=xlPasteFormulas
Selection.PasteSpecial Paste:=xlPasteFormats
Range("C10").Copy
Range("C8:C9").Select
Selection.PasteSpecial Paste:=xlPasteFormulas
Range("H9:AK9").Copy
Range("H8:AK8").Select
Selection.PasteSpecial Paste:=xlPasteAll
...instead of:
Range("A9:AK9").Copy
Range("A8:AK8").PasteSpecial xlPasteValuesAndNumberFormats
Range("C10").Copy
Range("C8:C9").PasteSpecial Paste:=xlPasteFormulas
Range("H9:AK9").Copy Range("H8:AK8")
All of this would be more clear by Googling the documentation for each command you're unfamiliar with, such as:
Range.Copy Method (Excel)
Range.PasteSpecial Method (Excel)
XlPasteType Enumeration (Excel)
All the ActiveCell and ThisWorkbook references are troublesome but again, I'm not sure what to do with them since I don't know your workbook.
Indentation (and general organization) are very important as well. It may not change the way that the code runs, but it will help you (and others) track down existing & potential issues more easily.
Here is your code cleaned up as best as I could:
Option Explicit 'this line goes at the very top of the module
Private Sub insertButton_Click()
Dim i As Long, emptyRow As Long, SearchRange As Range, FindRow As Range, nomCM
nomCM = Empty
ActiveCell.EntireRow.Insert Shift:=xlDown
Range("A9:AK9").Copy
Range("A8:AK8").PasteSpecial xlPasteValuesAndNumberFormats
Range("C10").Copy
Range("C8:C9").PasteSpecial Paste:=xlPasteFormulas
Range("H9:AK9").Copy Range("H8:AK8")
Range("A8").RowHeight = 18.6
For i = 2 To ThisWorkbook.Sheets.Count
With Sheets(i)
emptyRow = .Range("A9").End(xlDown).Offset(0, 2).Row
.Range("A9:AL" & emptyRow).Sort Key1:=.Range("A9"), Order1:=xlAscending
Set SearchRange = .Range("A8", .Range("A200").End(xlUp))
Set FindRow = SearchRange.Find(nomCM, LookIn:=xlValues, LookAt:=xlWhole)
.Range("A" & FindRow.Row).Select
ActiveCell.EntireRow.Activate
End With
Next i
Sheets("Sheet2").Select
End Sub
as per my test, sorting actually doesn't change other sheet direct references
so you may want to use OFFSET to keep referencing the actual current row index
instead of:
=$C9-COUNTIF($E9:$P9;"CT")+'Sheet5'!$D9
use
=$C9-COUNTIF($E9:$P9;"CT")+ OFFSET('Sheet5'!$D1,ROW()-1,0)
I found a solution:
=INDIRECT(ADDRESS(ROW();4;3;1;"Sheet5"))
Where Row() will always refer to the actual cell's row.
Hope it will help you!

Excel VBA paste from visible cell selection error

I am still new to VBA, but I am trying to paste a copied selection of rows and columns from a different workbook to the current workbook. My issue is that it errors out when I try to paste I assume because the selection is larger than the destination selection. Below part of the code (I know, horrible and with selects):
dim i as long
Workbooks.Open Filename:="C:\Users\...\File1.xls"
Range("A15").Select
For i = 1 To n
ActiveCell.FormulaR1C1 = "=CONCATENATE(RC[1],RC[2])"
ActiveCell.Offset(1, 0).Select
Next i
Range("Q15").Select
For i = 1 To n
ActiveCell.FormulaR1C1 = "=VLOOKUP(RC[-16] ,'[file2.xlsm]DST'!C1:C18,1,0)"
ActiveCell.Offset(1, 0).Select
Next i
ActiveSheet.Range("$A$14:$Q$103").AutoFilter Field:=17, Criteria1:="#N/A"
Range("A1").End(xlDown).SpecialCells(xlCellTypeVisible).Copy
Windows("File2.xlsm").Activate
ThisWorkbook.Worksheets("sheet2").Activate
Range("B1").End(xlDown).Offset(1, -1).Select
'moves the active cell to the data end of column A
Debug.Print "Active cell is " & ActiveCell.Address(False, False)
'it puts the cursor correctly here, but it errors out after in the selection
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks:=False, Transpose:=False
Basically, this is part of a code that is adding a new column in a system export file(1), where a unique searching key composed of the second and third column is used later in a VLOOKUP formula to check if there are any missing products and if there are, those will be added in the reporting file(2), at the end of the data that is there. Column B is used as column A has a formula (another CONCATENATE that can't be used for the selection).
How can I make the selection work ?
The following code isn't the solution but it contains it.
Dim WbTarget As Workbook
Dim WsT As Worksheet
Dim Rng As Range
Set WbTarget = Workbooks("File2.xlsm") ' must be open
Set WsT = WbTarget.Worksheets("Sheet2")
Set Rng = WsT.Range("B1").End(xlDown).Offset(1, -1)
With ActiveSheet
.Range("$A$14:$Q$103").AutoFilter Field:=17, Criteria1:="#N/A"
.Range("A1").End(xlDown).SpecialCells(xlCellTypeVisible).Copy Destination:=Rng
End With
Basically, it avoids the PasteSpecial method which would require source and target ranges to be of identical size.
Its big flaw is its reference to ActiveSheet. You have code here to declare and set a workbook, a worksheet and a range. The target workbook, worksheet and range are never selected or activated. I recommend that you treat the source in the same way.
Set Option Explicit at the top of your code sheet. Remember that it is best practice to make all declarations at the beginning of a procedure and, if you like to allow me one more piece of advice, consider writing the results of worksheet functions into your worksheet rather than the worksheet functions.

Copy and Paste (transposed & values) a set range in a different sheet in the next empty row

I have some data in range P1:R13 on a sheet called Training Analysis.
I want to copy and paste these data on a second sheet called Foglio1. I want it to be just values. I need these data to be pasted in a range A2:M4, in other words I want it to be transposed.
I got the following code and it is working. But now, when I get new data I need to paste them under those I already have.
Sub add()
Dim lastrow As Long
lastrow = Sheets("Foglio1").Range("A65536").End(xlUp).Row ' or + 1
Range("P1:R13").Copy Destination:=Sheets("Foglio1").Range("A" & lastrow)
End Sub
It does the empty space but I don't know how to change it to make it transpose the data and give me only values.
Can you help me change it ? If you have new options its fine too.
Cheers
What you need to do when you have a question like this is to record a macro, understand how it works and then clean up the code.
This is what you will get after doing what you need manually and recording it:
Range("P1:R13").Select
Selection.Copy
Sheets("Foglio1").Select
Range("A1").Select
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=True
After you clean it up a bit and add determining the last row this is what you should get:
Dim lastRow As Long
Sheets("Training Analysis").Range("P1:R13").Copy
lastRow = Sheets("Foglio1").Range("a65536").End(xlUp).Row
Sheets("Foglio1").Range("A" & lastRow + 1).PasteSpecial Paste:=xlPasteValues, Transpose:=True
In this particular case you didn't know that you need to use the PasteSpecial method but this is okay: you don't need to remember the entire Excel object model by heart. You can use the 'record, clean up and modify' method whenever you are in a situation like this.
You could shorten it further and try:
Sub add()
Range("Foglio1!A2:M4").Value2 = Application.WorksheetFunction.transpose(Range("Training Analysis!P1:R13").Value2)
End Sub
This is, of course, adapted to this specific case, so, for further use, you must ensure you update the sheet names and ranges(if they change). You also have to check by yourself that the areas are equivalent (e.g. 15x2 to 5x6 cells). These checks can be added in the procedure, but the code above should do the trick for the moment.
EDIT: I saw your specification a bit too late. :)
Here is the adapted code, which should find the first available row on sheet "Foglio1", column A, and will paste the transposed values onto a 3x13 area. Give it a go.
Sub add2()
With Sheets("Foglio1")
.Cells(.Range("A" & .Rows.Count).End(xlUp).Row + 1, 1).Resize(3, 13).Value2 = _
Application.WorksheetFunction.Transpose(Sheets("Training Analysis").Range("P1:R13").Value2)
End With
End Sub
EDIT 2: updated add2 so that the source range would refer to sheet "Training Analysis" and prevent error# 1004.

Declaring last row references in Excel formulas through VBA

In an attempt to take one of my rudimentary programs, and develop it more I am in need of help referencing last row references in Excel formulas as well as dragging formulas down consistently to the last row of a document.
To elaborate I am attempting to reference the last row in an ever expanding mapping table in my vlookup formula. The reason I need this is because as this mapping table expands when I am no longer coding this program, I need my vlookup formula which will be generated every time I run the program to adapt to the ever changing size.
Also my more pressing issue is in regard to taking that vlookup formula and being able to drag it down to the last row of a worksheet. The worksheet will be static and the last row will range anywhere from 70,000 rows to 90,000 rows. I am trying to avoid loops in this scenario as this will already be a very demanding formula and I would hate to loop through each row.
Currently my rudimentary code looks like this (this was built as a proof of concept, I understand the current method isn't the most ingenious but it served its initial purpose).
Ath.Cells(1, x) = "Business"
Ath.Cells(2, x).Select
ActiveCell.FormulaR1C1 = "=IFERROR(VLOOKUP(RC[1],Mapping!R2C4:R264C5,2,0),VLOOKUP(LEFT(RC[1],2),Mapping!R1C3:R264C5,3,0))"
Ath.Range("d2").Copy
Range("d2:d90000").Select
ActiveSheet.Paste
Calculate
I namely want to change this
Ath.Range("d2").Copy
Range("d2:d90000").Select
ActiveSheet.Paste
and
ActiveCell.FormulaR1C1 = "=IFERROR(VLOOKUP(RC[1],Mapping!R2C4:R264C5,2,0),VLOOKUP(LEFT(RC[1],2),Mapping!R1C3:R264C5,3,0))"
Perhaps these?
Ath.Range("d2").Copy
Range("d2:d" & Range("D" & Rows.Count).End(xlUp).Row).Paste
ActiveCell.FormulaR1C1 = "=IFERROR(VLOOKUP(RC[1],Mapping!R2C4:R" & Sheets("Mapping").Range(ActiveCell.Offset(Rows.Count, -1)).End(xlUp).Row & "C5,2,0),VLOOKUP(LEFT(RC[1],2),Mapping!R1C3:R" & Sheets("Mapping").Range(ActiveCell.Offset(Rows.Count, -1)).End(xlUp).Row & "C5,3,0))"
Combining Dans answer with work of my own I have developed a solution.
Sub Formulas()
Dim Map As Worksheet
Dim Ath As Worksheet
Dim last As Long
Set Ath = Sheets("Athena IBT TEST")
Set Map = Sheets("Mapping")
last = Map.Cells(Rows.Count, "D").End(xlUp).Row
ActiveCell.FormulaR1C1 = "=IFERROR(VLOOKUP(RC[1],Mapping!R1C1:R" & last & "C4,4,0),IFERROR(VLOOKUP(LEFT(RC[1],3),Mapping!R1C2:R" & last & "C4,3,0),VLOOKUP(LEFT(RC[1],3),Mapping!R1C3:R" & last & "C4,2,0)))"
End Sub

VBA - Copy and Paste Dynamic Range with Dynamic Start Point

I am very new to the VBA community and usage so my illiteracy is a bit embarrassing. I work in a lab that routinely deals with very large data output files. In order to statistically analyze these data files we often have to rearrange the output data into a more statistically friendly format. Therein lies my problem.
I have created and VBA that does this for a very specific dataset, copying and paste transposing 5 data points at a time. I would like help in creating something that allows me to have a more generic approach to this where I might be able to enter the number of study time points (typically between 3 and 10) and the number of study participants (between 10 and 100) and still get the copy/paste transpose done on the correct sheet.
What I have in my specific VBA is below. I basically have this done manually all the way to a range of B208:212 and all the way through Sheet 13.
Sheets("Raw Data").Select
Range("B3:B7").Select
Selection.Copy
Sheets("Sheet1").Select
Range("D2").Select
Selection.PasteSpecial Paste:=xlPasteAll, Operation:=xlNone, SkipBlanks:= _
False, Transpose:=True
What this does is copies five data points for one study participant, goes to my desired sheet, and paste transposes in the row corresponding with my study participant. I need to do this for up 100 study participants, each beginning on its own row starting with D2.
Sorry this is confusing. I am working on posting more clarification below.
Sheets("Raw Data").Select
Range("B3:B7").Select
Selection.Copy
Sheets("Sheet1").Select
Range("D2").Select
Selection.PasteSpecial Paste:=xlPasteAll, Operation:=xlNone, SkipBlanks:= _
False, Transpose:=True
reduces to
Sheets("Sheet1").Range("D2").Resize(5, 1).Value = _
Application.Transpose(Sheets("Raw Data").Range("B3").Resize(1, 5).Value)
Taking that as a starting point, you can declare some variables (or better, use Constants) for the "5", etc, but you'd need to add some more details to your question, including what dtermines where the next "paste" point is. you mention multiple sheets but it's not clear how those are involved in the operation.
Eg:
Sub Tester()
Const DATA_PTS As Long = 5
Dim rngCopy As Range, rngPaste As Range
'start point for source data
Set rngCopy = Sheets("Raw Data").Range("B3").Resize(DATA_PTS, 1).Value
Do While Application.CountA(rngCopy) > 0
'Set rngPaste = ? 'what determines where data is copied to?
rngPaste.Resize(1, DATA_PTS).Value = _
Application.Transpose(rngCopy.Value)
'next source range
Set rngCopy = rngCopy.Offset(DATA_PTS, 0)
Loop
End Sub