VBA - capacity overflow error - vba

I have the following code that is causing a
capacity overflow error type 6
due to the code between '------------------------------------'. I will appreciate your help :)!
I was not able to solve it with other discussion.
Sub Calculate_Mix()
Dim rngUsernameHeader As Range
Dim rngHeaders As Range
Dim rngAddress As Range
Dim rng_R1 As Range
Dim rng_delisted As Range
Dim ws As Worksheet
Dim value As Long
Set ws = ThisWorkbook.Sheets("Sheet1")
Set rngHeaders = Range("1:1") 'Looks in entire first row.
Set rngUsernameHeader = rngHeaders.Find(what:="VAl MAT'Mar18", After:=Cells(1, 1))
rngUsernameHeader.Offset(0, 1).EntireColumn.Insert
rngUsernameHeader.Offset(0, 1).value = "Delisted"
rngUsernameHeader.Offset(0, 2).EntireColumn.Insert
rngUsernameHeader.Offset(0, 2).value = "New Launches"
rngUsernameHeader.Offset(0, 3).EntireColumn.Insert
rngUsernameHeader.Offset(0, 3).value = "Price_17"
rngUsernameHeader.Offset(0, 4).EntireColumn.Insert
rngUsernameHeader.Offset(0, 4).value = "Price_18"
For Each Cel In Range("F2", Range("F2").End(xlDown))
If Cel > 0 And Cel.Offset(0, 1) = 0 Then
Cel.Offset(0, 2).value = Cel.value
Else: Cel.Offset(0, 2).value = 0
End If
If Cel = 0 And Cel.Offset(0, 1) > 0 Then
Cel.Offset(0, 3).value = Cel.Offset(0, 1).value
Else: Cel.Offset(0, 3).value = 0
End If
Next Cel
'------------------------------------'
For Each Cel In Range("H2", Range("H2").End(xlDown))
If Cel = 0 And Cel.Offset(0, 1) = 0 Then
value = Cel.Offset(0, -2).value / Cel.Offset(0, -4).value
Cel.Offset(0, 2).value = value
Else: Cel.Offset(0, 2).value = 0
End If
Next Cel
'------------------------------------'
End Sub

You've declared value (bad variable name, by the way) as Long. You'll get an overflow error if you try to assign a decimal value to an integer variable (which may well be happening with this line:
value = Cel.Offset(0, -2).value / Cel.Offset(0, -4).value
Try declaring value as Double
Better still, rename and declare dMyValue as Double

Related

VBA loop to change cell value (pos/neg) and font color based on adjacent cell

I'm very new to VBA and I'm having trouble understanding how to accomplish 2 tasks in one loop. I greatly appreciate your help.
I have been able to change the numeric value in column 2 based on data in column 3, but I dont understand how to change the font of the negative values to red.
The size of the table changes monthly based on days in the month (if that matters). Thank you!
Dim AQRng As Range, Cel As Range, p_AQend As Object
Set p_AQend = Range("AQ2").End(xlDown)
Set AQRng = Range("AQ2", p_AQend)
For Each Cel In AQRng
If Cel.Value <> 0 Then
If Cel.Offset(0, 1).Text = "Negative" Then
Cel.Value = Abs(Cel.Value) * -1
ElseIf Cel.Offset(0, 1) <> "Negative" Then
Cel.Value = Abs(Cel.Value)
End If
End If
Next Cel
Try this:
Sub Test()
Dim rng As Range, cl As Range
Set rng = Range("AQ2:QA" & Range("A2").End(xlDown).Row)
For Each cl In rng
If cl.Value <> 0 Then
If cl.Offset(0, 1) = "Negative" Then
cl = Abs(cl) * -1
cl.Font.Color = vbRed
Else
cl = Abs(cl)
End If
End If
Next cl
End Sub
Try this : I added Cel.Font.Color = RGB(255, 0, 0) in your negative condition
Dim AQRng As Range, Cel As Range, p_AQend As Object
Set p_AQend = Range("AQ2").End(xlDown)
Set AQRng = Range("AQ2", p_AQend)
For Each Cel In AQRng
If Cel.Value <> 0 Then
If Cel.Offset(0, 1).Text = "Negative" Then
Cel.Value = Abs(Cel.Value) * -1
Cel.Font.Color = RGB(255, 0, 0)
ElseIf Cel.Offset(0, 1) <> "Negative" Then
Cel.Value = Abs(Cel.Value)
End If
End If
Next Cel
I hope I'm understanding this correctly. The Cel that you are changing the value on (by multiplying by -1) is the Cel you would like to change the color on, correct?
If so,
For Each Cel In AQRng
If Cel.Value <> 0 Then
If Cel.Offset(0, 1).Text = "Negative" Then
Cel.Value = Abs(Cel.Value) * -1
Cel.Font.ColorIndex = 3
ElseIf Cel.Offset(0, 1) <> "Negative" Then
Cel.Value = Abs(Cel.Value)
End If
End If
Next Cel
I have added a line under your negative condition:
Cel.Font.ColorIndex = 3. The .Font.ColorIndex will change the color of the font to whatever you choose - ColorIndex = 3 happens to change it to red.
Please Read Here for more information on the various font colors you can choose using ColorIndex.
here's a no-loop solution:
With Range("AR2", cells(Rows.Count, "AR").End(xlUp))
.Replace what:="Positive", replacement:="", lookat:=xlWhole
With .SpecialCells(xlCellTypeBlanks)
.Offset(, 1).Value = .Offset(, -1).Value
.Offset(, -1).FormulaR1C1 = "=ABS(RC[2])"
.Value = "Positive"
End With
.Replace what:="Negative", replacement:="", lookat:=xlWhole
With .SpecialCells(xlCellTypeBlanks)
.Offset(, 1).Value = .Offset(, -1).Value
.Offset(, -1).FormulaR1C1 = "=-ABS(RC[2])"
.Value = "Negative"
.Font.Color = vbRed
End With
.Offset(, -1).Value = .Offset(, -1).Value
.Offset(, 1).ClearContents
End With
this supposes column AS can be written, but the code is easily changeable to use a different helper column
Fastest way to change negative values to red.
Columns("AQ:AQ").NumberFormat = "0.00_ ;[Red]-0.00 "

Using rangefind

I have three sheets, sheet S, Sheet P and Sheet Data.
I first copy the column of Sheet S to Sheet Data. Then in column E of sheet Data, I look for the ID. The ID In column E of data sheet, matches with the column A of P sheet, then I copy the corresponding ID.
The problem here is the Sheet data contains 214 rows, while sheet P contains 1110.
while comparing the ID, there are two different ID from row 870 and 871, which are not copied, even though they are same.
Could someone guide what could be the reason ?
Sub lookup()
Dim lLastrow, totalrows As Long
Dim rng As Range
Dim i As Long
'Copy lookup values from S to Data
With Sheets("S")
lLastrow = .Cells(.Rows.count, 1).End(xlUp).Row
.Range("P5:P" & lLastrow).Copy Destination:=Sheets("Data").Range("E5")
.Range("G5:G" & lLastrow).Copy Destination:=Sheets("Data").Range("H5")
End With
totalrows = Sheets("P").Cells(Sheets("P").Rows.count, "A").End(xlUp).Row
For i = 5 To lLastrow
'Search for the value on P_APQP
With Sheets("P")
Set rng = .Columns(1).Find(Sheets("Data").Cells(i, 5).Value & "*", lookat:=xlWhole)
End With
'If it is found put its value on the destination sheet
If Not rng Is Nothing Then
With Sheets("Data")
.Cells(i, 6).Value = rng.Value
.Cells(i, 1).Value = rng.Offset(0, 1).Value
.Cells(i, 2).Value = rng.Offset(0, 2).Value
.Cells(i, 3).Value = rng.Offset(0, 3).Value
.Cells(i, 4).Value = rng.Offset(0, 9).Value
.Cells(i, 9).Value = rng.Offset(0, 10).Value
.Cells(i, 13).Value = rng.Offset(0, 6).Value
.Cells(i, 14).Value = rng.Offset(0, 5).Value
.Cells(i, 15).Value = rng.Offset(0, 4).Value
.Cells(i, 16).Value = rng.Offset(0, 8).Value
End With
End If
Next i
End Sub
I'll post the whole code. I also made an adjustment to your first line of declarations - as you had it, only totalrows was being declared as Long. You have to spell each one out I'm afraid.
Sub lookup()
Dim lLastrow As Long, totalrows As Long
Dim rng As Range
Dim i As Long
With Sheets("S")
lLastrow = .Cells(.Rows.Count, 1).End(xlUp).Row
.Range("P5:P" & lLastrow).Copy Destination:=Sheets("Data").Range("E5")
.Range("G5:G" & lLastrow).Copy Destination:=Sheets("Data").Range("H5")
End With
totalrows = Sheets("P").Cells(Sheets("P").Rows.Count, "A").End(xlUp).Row
For i = 5 To lLastrow
'Search for the value on P_APQP
With Sheets("P")
'amended below
Set rng = .Columns(1).Find(Trim(Sheets("Data").Cells(i, 5).Value) & "*", lookat:=xlWhole)
End With
'If it is found put its value on the destination sheet
If Not rng Is Nothing Then
With Sheets("Data")
.Cells(i, 6).Value = rng.Value
.Cells(i, 1).Resize(, 3).Value = rng.Offset(0, 1).Value
.Cells(i, 2).Value = rng.Offset(0, 2).Value
.Cells(i, 3).Value = rng.Offset(0, 3).Value
.Cells(i, 4).Value = rng.Offset(0, 9).Value
.Cells(i, 9).Value = rng.Offset(0, 10).Value
.Cells(i, 13).Value = rng.Offset(0, 6).Value
.Cells(i, 14).Value = rng.Offset(0, 5).Value
.Cells(i, 15).Value = rng.Offset(0, 4).Value
.Cells(i, 16).Value = rng.Offset(0, 8).Value
End With
End If
Next i
End Sub

VBA Code for Identifying if cell contains with loop

So currently I am trying to come up with a if statement. Basically if A3 has any text value I want it to equal awesome. I want to loop this command with the last column in mind.
Sub Criteria
If Range("A2") = "Feedback" And Range("A3") = "**" Then
Range("A1") = "Awesome"
Else
Range("A1") = ""
End If
End sub
(This is the code I came up with can someone help me make it cleaner/faster)
Sub Status()
lastrow = Rows(Rows.Count).End(xlUp).Row
For i = 2 To lastrow
If Cells(i, 1) = "Onsite" And Not IsEmpty(Cells(i, 2)) Then
Cells(i, 3) = "Feedback"
Else
If Cells(i, 1) = "Phone" And Not IsEmpty(Cells(i, 2)) Then
Cells(i, 3) = "Feedback"
Else
If Cells(i, 1) = "Phone" And IsEmpty(Cells(i, 2)) Then
Cells(i, 3) = "Pending Next Step"
Else
If Cells(i, 1) = "Onsite" And IsEmpty(Cells(i, 2)) Then
Cells(i, 3) = "Pending Decision"
End If
End If
End If
End If
Next i
End Sub
Try using Option Explicit also set your worksheet so your not running the code on wrong sheet or to avoid a error
Option Explicit
Public Sub Status()
Dim Sht As Worksheet
Dim rng As Range
Set Sht = ThisWorkbook.Sheets("Sheet1")
For Each rng In Sht.Range("A2", Sht.Range("A9999").End(xlUp))
Debug.Print rng.Address ' print on immed win
DoEvents ' For Debuging
If rng.Value = "Onsite" And rng.Offset(0, 1).Value > 0 Then
rng.Offset(0, 2).Value = "Feedback"
ElseIf rng.Value = "Onsite" And rng.Offset(0, 1).Value = "" Then
rng.Offset(0, 2).Value = "Pending Decision"
End If
If rng.Value = "Phone" And rng.Offset(0, 1).Value > 0 Then
rng.Offset(0, 2).Value = "Feedback"
ElseIf rng.Value = "Phone" And rng.Offset(0, 1).Value = "" Then
rng.Offset(0, 2).Value = "Pending Next Step"
End If
Next
Set Sht = Nothing
Set rng = Nothing
End Sub
Range.Offset Property (Excel)
Syntax: expression.Offset(RowOffset, ColumnOffset)
Returns a Range object that represents a range that?s offset from the specified range.

Unable to copy from a set sheet when looping through data

I had an earlier question which was kindly answered and I was given the following code which worked perfectly in a test environment where the code was looping through 3 sheets with only 1 sheet of data and 3 columns.
Below is my ammended code to go through 16 columns. The issue however I believe I am facing is when opening a sheet in the live environment the sub workbooks all contain 4 tabs which are "Lookup", "Detail", "Summary" and "Calls".
The code contains For Each sheet In ActiveWorkbook.Worksheets
I am wanting to only take the data in the below code from each workbook in the loop in the "Calls" tab. Can anyone recommend any change to the existing loop to do this?
Sub Theloopofloops()
Dim wbk As Workbook
Dim Filename As String
Dim path As String
Dim rCell As Range
Dim rRng As Range
Dim wsO As Worksheet
Dim sheet As Worksheet
Set sheet = ActiveWorkbook.Sheets(Sheet2)
path = "M:\Documents\Call Logger\"
Filename = Dir(path & "*.xlsm")
Set wsO = ThisWorkbook.Sheets("Master")
Do While Len(Filename) > 0
DoEvents
Set wbk = Workbooks.Open(path & Filename, True, True)
For Each sheet In ActiveWorkbook.Worksheets
Set rRng = sheet.Range("A2:A20000")
For Each rCell In rRng.Cells
If rCell <> "" And rCell.Value <> vbNullString And rCell.Value <> 0 Then
wsO.Cells(wsO.Rows.Count, 1).End(xlUp).Offset(1, 0).Value = rCell
wsO.Cells(wsO.Rows.Count, 1).End(xlUp).Offset(0, 1).Value = rCell.Offset(0, 1)
wsO.Cells(wsO.Rows.Count, 1).End(xlUp).Offset(0, 2).Value = rCell.Offset(0, 2)
wsO.Cells(wsO.Rows.Count, 1).End(xlUp).Offset(0, 3).Value = rCell.Offset(0, 3)
wsO.Cells(wsO.Rows.Count, 1).End(xlUp).Offset(0, 4).Value = rCell.Offset(0, 4)
wsO.Cells(wsO.Rows.Count, 1).End(xlUp).Offset(0, 5).Value = rCell.Offset(0, 5)
wsO.Cells(wsO.Rows.Count, 1).End(xlUp).Offset(0, 6).Value = rCell.Offset(0, 6)
wsO.Cells(wsO.Rows.Count, 1).End(xlUp).Offset(0, 7).Value = rCell.Offset(0, 7)
wsO.Cells(wsO.Rows.Count, 1).End(xlUp).Offset(0, 8).Value = rCell.Offset(0, 8)
wsO.Cells(wsO.Rows.Count, 1).End(xlUp).Offset(0, 9).Value = rCell.Offset(0, 9)
wsO.Cells(wsO.Rows.Count, 1).End(xlUp).Offset(0, 10).Value = rCell.Offset(0, 10)
wsO.Cells(wsO.Rows.Count, 1).End(xlUp).Offset(0, 11).Value = rCell.Offset(0, 11)
wsO.Cells(wsO.Rows.Count, 1).End(xlUp).Offset(0, 12).Value = rCell.Offset(0, 12)
wsO.Cells(wsO.Rows.Count, 1).End(xlUp).Offset(0, 13).Value = rCell.Offset(0, 13)
wsO.Cells(wsO.Rows.Count, 1).End(xlUp).Offset(0, 14).Value = rCell.Offset(0, 14)
wsO.Cells(wsO.Rows.Count, 1).End(xlUp).Offset(0, 15).Value = rCell.Offset(0, 15)
End If
Next rCell
Next sheet
wbk.Close False
Filename = Dir
Loop
End Sub
Instead of using the loop, just replace the For Each sheet ... line with
Set sheet = wbk.Worksheets("Calls")
(and remove Next sheet)
You could even shorten that and use
Set rRng = wbk.Worksheets("Calls").Range("A2:A20000")
or even skip that and use
For Each rCell In wbk.Worksheets("Calls").Range("A2:A20000").Cells
You can also shorten the copying by using
wsO.Cells(wsO.Rows.Count, 1).End(xlUp).Offset(1, 0).Resize(1, 16).Value = rCell.Resize(1, 16).Value
you may be after what follows:
Option Explicit
Sub Theloopofloops()
Dim wbk As Workbook
Dim Filename As String
Dim path As String
Dim rCell As Range
Dim wsO As Worksheet
path = "M:\Documents\Call Logger\"
Filename = Dir(path & "*.xlsm")
Set wsO = ThisWorkbook.Sheets("Master")
Do While Len(Filename) > 0
DoEvents
Set wbk = Workbooks.Open(path & Filename, True, True)
For Each rCell In ActiveWorkbook.Worksheets("Calls").Range("A2:A20000")
If rCell <> "" And rCell.Value <> vbNullString And rCell.Value <> 0 Then
wsO.Cells(wsO.Rows.Count, 1).End(xlUp).Offset(1, 0).Resize(, 16).Value = rCell.Resize(, 16).Value
End If
Next rCell
wbk.Close False
Filename = Dir
Loop
End Sub

Cleaning up a messy VBA formula

I'm very new to Excel VBA (started about a day ago!) but I'm slowly struggling through. I've created a formula that copies a selection of three cells to another part of the sheet if column D contains the value "(2)", then assigns the value "0" to some more cells in the same row.
The trouble is, I've used a mixture of recording and typing my macro so the end result is pretty messy. Currently the macro takes a while to complete (it moves everything around and then a little hourglass appears for a good 15 seconds or so). I'm assuming this is in part due to my use of "Select" (I'm aware this is a bad thing!) but I'm just trying to work out what I can strip from the formula to make it more efficient while retaining the same outcome.
Sub MoveNames()
Dim SrchRng As Range, cel As Range
Set SrchRng = Range("D:D")
For Each cel In SrchRng
If InStr(1, cel.Value, "(2)") > 0 Then
cel.Offset(0, 1).Range("A1:C1").Select
Selection.Copy
ActiveCell.Offset(-1, 40).Range("A1").Select
ActiveSheet.Paste
Application.CutCopyMode = False
ActiveCell.Offset(0, -4) = "0"
ActiveCell.Offset(0, -5) = "0"
ActiveCell.Offset(0, -6) = "0"
ActiveCell.Offset(0, -7) = "0"
ActiveCell.Offset(0, -10) = "0"
ActiveCell.Offset(0, -12) = "0"
End If
Next cel
End Sub
Any help would be much appreciated.
If I understand what you're trying to do, this should do the same thing without having to use any objects or any copy/paste methods:
Sub MM_MoveNames()
For i = 2 To Cells(Rows.count, 4).End(xlUp).Row
If InStr(Cells(i, 4).value, "(2)") Then
Cells(i - 1, 44).Resize(1, 3).value = Cells(i, 5).Resize(1, 3).value
Cells(i, 37).Resize(1, 4).value = 0
Cells(i, 34).value = 0
Cells(i, 32).value = 0
End If
Next
End Sub
More importantly though - if your code is working, and you just want advice for improvements then you should post your code on Code Review, not on Stack Overflow.
try this
Sub MoveNames()
Dim SrchRng As Range
lastrow = Range("D" & Rows.Count).End(xlUp).Row
Set SrchRng = Range("D1:D" & lastrow)
For Each cel In SrchRng
If InStr(1, cel.Value, "(2)") > 0 Then
With cel.Offset(0, 1).Range("A1:C1")
.Copy cel.Offset(-1, 40).Range("A1")
End With
With cel.Offset(-1, 40)
.Offset(0, -4) = "0"
.Offset(0, -5) = "0"
.Offset(0, -6) = "0"
.Offset(0, -7) = "0"
.Offset(0, -10) = "0"
.Offset(0, -12) = "0"
End With
End If
Next cel
End Sub
Give this a shot, you can definitely clean it up more by combining the multiple offsets and ranges.
Sub test()
Dim rngIndex As Range
For Each rngIndex In Range("D:D")
If InStr(1, rngIndex.Value, "(2)") > 0 Then
rngIndex.Offset(0, 1).Range("A1:C1").Copy _
rngIndex.Offset(0, 1).Range("A1:C1").Offset(-1, 40).Range("A1")
With rngIndex.Offset(0, 1).Range("A1:C1")
Range(.Offset(0, -4), .Offset(0, -7)).Value = 0
.Offset(0, -10) = "0"
.Offset(0, -12) = "0"
End With
End If
Next rngIndex
End Sub
Instead of going throug each cell in column D, you can go through just the used range, like this:
Set SrchRng = Range("D1:D" & ActiveSheet.UsedRange.Rows.Count)
Which should speed it up quite a bit.
You can use Select, I found that easier when I was learning VBA myself. In time you will learn to avoid it.
To speed up macro execution when using Select, you can add Application.ScreenUpdating = False at the beginning and Application.ScreenUpdating = True at the end of your procedure.
Disabling automatic calculations is also beneficial, you can do it by adding Application.Calculation = xlManual and Application.Calculation = xlManual at the beginning and end respectively.
Hope that helps. if you have more questions, just ask.
My turn - instead of looking at each cell, just jump to the ones containing (2).
Sub MoveNames()
Dim SrchRng As Range, cel As Range
Dim rFound As Range
Dim sFirstAddress As String
Set SrchRng = ThisWorkbook.Worksheets("Sheet1").Range("D:D")
Set rFound = SrchRng.Find("(2)", LookIn:=xlValues, LookAt:=xlPart, SearchDirection:=xlNext)
If Not rFound Is Nothing Then
sFirstAddress = rFound.Address
Do
rFound.Offset(, 1).Resize(, 3).Copy Destination:=rFound.Offset(-1, 41)
rFound.Offset(-1, 34).Resize(, 4) = 0
rFound.Offset(-1, 29) = 0
rFound.Offset(-1, 31) = 0
Set rFound = SrchRng.FindNext(rFound)
Loop While Not rFound Is Nothing And rFound.Address <> sFirstAddress
End If
End Sub