Overflow Error 6 with the following Excel 2010 VBA - excel

The following code will format my template correctly the way I want. However, in the event the template is empty and a user hits the prep upload button on the sheet, I will receive an Overflow Error 6. Is there any way to remove what is causing this error?
Sub PrepForUpload()
Dim cel As Range, rng As Range
Set rng = Range("A2", Range("A65536").End(xlUp))
For Each cel In rng
If cel.Value = "" Then
If cel.Offset(, 2).Value = "" Then
cel.EntireRow.Delete
End If
End If
Next cel
Dim rowNumber As Integer
With Sheets("Initiatives")
If Len(.Cells(2, 1)) = 0 Then
rowNumber = .Cells(2, 1).End(xlDown).End(xlDown).Row + 1
Else: rowNumber = .Cells(2, 1).End(xlDown).Row + 1
End If
.Rows(rowNumber & ":" & .Rows.Count).Clear
End With
End Sub
Debug points to the following line as the issue:
rowNumber = .Cells(2, 1).End(xlDown).End(xlDown).Row + 1
Thanks
Ryan

You are getting an overflow because Integer in VBA is a 16 bit signed number (max value of 32767). Regardless of the version of excel, you have a minimum of 65535 rows and most likely more if you are using the XLSX file format. You need to change rowNumber to a Long
And you also have to code around the blank worksheet scenerio. When you call this line:
rowNumber = .Cells(2, 1).End(xlDown).End(xlDown).Row + 1
and the worksheet is blank, .End(xlDown) will return the last possible row in the worksheet, which in the case of Excel 2010 (and Excel 2007) is 1048576. Once you change rowNumber to a Long you will no longer get the overflow error, but you will run into a problem with this line:
.Rows(rowNumber & ":" & .Rows.Count).Clear
This is because you are trying to select a range (row 1048577) that does not exist (hence the type mismatch). You need to add a line of code to work around this scenario. Either check initially for a blank worksheet, or check for row > 1048576.
The simplest thing to do is to just add a line to check this:
If rowNumber <= 1048576 Then
.Rows(rowNumber & ":" & .Rows.Count).Clear
End If

Change rowNumber to Long then add 1& or use CLng to get rid of the 'type-mismatch` error.
rowNumber = CLng(.Cells(2, 1).End(xlDown).End(xlDown).Row + 1)
or
rowNumber = .Cells(2, 1).End(xlDown).End(xlDown).Row + 1&

Can you show us what your data looks like in column A? You can also try this code, which test for the number of lines before attempting to get the row number
Dim cel As Range, rng As Range
If Application.WorksheetFunction.CountA(Columns(1)) <= 1 Then
MsgBox "No lines"
Exit Sub
End If
Set rng = Range("A2", Cells(Rows.Count, 1).End(xlUp))
For Each cel In rng
If Len(cel.Value) = 0 Then
If Len(cel.Offset(, 2).Value) = 0 Then cel.EntireRow.Delete
End If
Next cel
Dim rowNumber As Long
With Sheets("Initiatives")
If Application.WorksheetFunction.CountA(.Columns(1)) <= 1 Then
MsgBox "No lines in sheet Initiative"
Exit Sub
End If
If Len(.Cells(2, 1)) = 0 Then
rowNumber = .Cells(2, 1).End(xlDown).End(xlDown).Row + 1
Else: rowNumber = .Cells(2, 1).End(xlDown).Row + 1
End If
.Rows(rowNumber & ":" & .Rows.Count).Clear
End With

Related

How can I compare cells in different rows and insert-right if lower cell if not the same?

How can I compare cells in two rows and and match the lower cell value to the upper cell value, if the two are different? Here is some the same data I am working with and what I hope to see after the code runs.
Before:
[ID_GLOBAL], [ID_UNIQUE], [ID_REAL], [ID_1], [ID_2], [GAS_ADJ], [OBJ_ADJ]
[ID_GLOBAL], [ID_UNIQUE], [ID_REAL], [GAS_ADJ], [OBJ_ADJ]
After:
[ID_GLOBAL], [ID_UNIQUE], [ID_REAL], [ID_1], [ID_2], [GAS_ADJ], [OBJ_ADJ]
[ID_GLOBAL], [ID_UNIQUE], [ID_REAL], NULL AS [ID_1], NULL AS [ID_2], [GAS_ADJ], [OBJ_ADJ]
I think the code will basically look like this, but I haven't gotten the insert-right working properly.
Sub CompareCellsDiffRows()
Dim bothrows As Range, i As Integer
Set bothrows = Selection
With bothrows
For i = 1 To .Columns.Count
If Not StrComp(.Cells(1, i), .Cells(2, i), vbBinaryCompare) = 0 Then
' magic happens here
End If
Next i
End With
End Sub
As you may have guessed, I'm dealing with hundreds of fields in several tables and trying to Union everything together, so all these field names have to match up in the correct order.
Thanks.
I am assuming, as per your example, that the first row is the one that will be always complete.
Sub CompareRowDifferences()
Dim sht As Worksheet
Dim i, LastColumn As Long
Set sht = ThisWorkbook.Worksheets("Transposed Fields")
LastColumn = sht.Cells.SpecialCells(xlLastCell).Column
With sht
For i = 1 To LastColumn
If StrComp(.Cells(1, i), .Cells(2, i), vbBinaryCompare) <> 0 Then
.Cells(2, i).Insert Shift:=xlToRight
.Cells(2, i).Value2 = "NULL AS " & .Cells(1, i).Value2
End If
Next i
End With
End Sub
Hope it helps
Regarding your second question (if they are not ordered) and assuming always that the first line is the ones that rules...
Sub CompareRowDifferences()
Dim sht As Worksheet
Dim i, j, LastColumn As Long
Set sht = ThisWorkbook.Worksheets("Transposed Fields")
LastColumn = sht.Cells.SpecialCells(xlLastCell).Column
j = 0
With sht
For i = 1 To LastColumn
Test = Application.WorksheetFunction.CountIf(Range _
(Cells(2, i), Cells(2, LastColumn + j)), .Cells(1, i).Value2)
If Test >= 1 Then
.Cells(2, i).Insert Shift:=xlToRight
.Cells(2, i).Value2 = .Cells(1, i).Value2
Else
.Cells(2, i).Insert Shift:=xlToRight
.Cells(2, i).Value2 = "NULL AS " & .Cells(1, i).Value2
End If
j = j + 1
Next i
Range(Cells(2, LastColumn), Cells(2, LastColumn + j)).ClearContents
End With
End Sub
This procedure identifies and uses the row with a higher number of fields (i.e. no-empty cells), and uses it as "model" to update the other row regardless of the position of the fields in the other row.
Sub Headers_Comparison(rInput As Range)
Dim aOut As Variant, aSrc As Variant, aTrg As Variant
Dim bMatch As Byte, bRow As Byte, b As Byte
With WorksheetFunction
Rem Validate Fields in Rows
If .CountA(rInput.Rows(1)) > .CountA(rInput.Rows(2)) Then
bRow = 2
aSrc = .Transpose(.Transpose(rInput.Rows(1).Value2))
aTrg = .Transpose(.Transpose(rInput.Rows(2).Value2))
Else
bRow = 1
aSrc = .Transpose(.Transpose(rInput.Rows(2).Value2))
aTrg = .Transpose(.Transpose(rInput.Rows(1).Value2))
End If
aOut = aTrg
For b = 1 To UBound(aSrc)
bMatch = 0
On Error Resume Next
bMatch = .Match(aSrc(b), aTrg, 0)
On Error GoTo 0
aOut(b) = IIf(bMatch > 0, vbNullString, "NULL AS ") & aSrc(b)
Next: End With
rInput.Rows(bRow).Value = aOut
End Sub
It should be called in this manner:
Call Headers_Comparison(rSel) 'update with required range
I think I just figured it out!
Sub CompareRowDifferences()
Dim i As Integer
Dim sht As Worksheet
Dim LastColumn As Long
Set sht = ThisWorkbook.Worksheets("Transposed Fields")
LastColumn = sht.UsedRange.Columns(sht.UsedRange.Columns.Count).Column
For i = 1 To LastColumn
If Not StrComp(sht.Cells(1, i), sht.Cells(2, i), vbBinaryCompare) = 0 Then
' magic happens here
Set Rng = sht.Cells(2, i)
Rng.Insert Shift:=xlToRight
sht.Cells(2, i).Value = "NULL AS " & sht.Cells(1, i).Value
End If
Next i
End Sub
This seems to work. Although, this is a pretty simple solution. I understand it would be much more complex if the order of names the lower row changed. This works ONLY because the names in row 2 match the names in row 1, there are just fewer names. I would love to see what the code would look like if the order of the row 2 names was switch around, compared to the row 1 names.

Application-defined or object defined error

All,
I am receiving the error "Application defined or object defined error" for a private sub that I have written. The code is below:
Private Sub CommandButton3_Click()
Dim MyLastRow As Long
Dim i As Long
Dim cellmatch
'Find the last row
MyLastRow = Cells(Rows.Count, "A").End(xlUp).Row
'Define our comparison
cellmatch = Application.Match(Cells(i, "A").Value, Range(Cells(i, "C")).Value, 0)
'Compare Raw Data cell to Stock column and find a match
For i = 2 To MyLastRow
If IsError(cellmatch) Then
Cells(i, 2) = "Not in Stock"
Else
Cells(i, 2) = "-"
End If
Next i
End Sub
I have tried several things I found on the forums such us specifying the worksheet
Application.WorksheetFuncion.Match.....
I've also tried point to the cell or range such as:
Range(.Cells(i,"C"))....
or
.Match(.Cells(i,"A"))...
But I keep getting the same error. All of this is happening on the same sheet and I'm not trying to do anything fancy like copying. I am simply asking if a match is NOT found, then label as such, else, label it with a dash (done like this for clarity). I am sure it's something very simple but I am new to coding in VBA. Any help is much appreciated.
Thanks!
Your code requires change of this code line.
cellmatch = Application.Match(Cells(i, "A").Value, Range(Cells(i, "C")).Value, 0)
TO
'Adjust Sheetname as per your requirements instead of "Sheet1"
cellmatch = Application.Match(Cells(i, "A").Value, Worksheets("Sheet1").Columns(3), 0)
EDIT
Main problem is coming in your program because of the following code fragment.
Range(Cells(i, "C")).Value
If we refer to MSDN Documenation
Range.Cells Property (Excel)
It mentions exammples of correct syntax of usage.
Typical example is
Set r = Range("myRange")
For n = 1 To r.Rows.Count
If r.Cells(n, 1) = r.Cells(n + 1, 1) Then
MsgBox "Duplicate data in " & r.Cells(n + 1, 1).Address
End If
Next n
So it translates to Range("myRange").Cells(n,1)
and not
Range(Cells(i, "C"))
It will give correct results as shown in the snapshot.
I believe this is what you are looking for:
Option Explicit
Private Sub CommandButton3_Click()
Dim lngRow As Long
Dim rngFound As Range
Dim lngLastRow As Long
Dim shtCurrent As Worksheet
'Set the sheet to work on
Set shtCurrent = ThisWorkbook.Worksheets("Sheet1")
With shtCurrent
'Find the last row
lngLastRow = .Cells(.Rows.Count, "A").End(xlUp).Row
'Exit if the last row is 2 or smaller
If lngLastRow <= 2 Then
MsgBox "Nothing to compare!" & Chr(10) & "Aborting..."
Exit Sub
End If
'Compare Raw Data cell to Stock column and find a match
For lngRow = 2 To lngLastRow
'Only compare if there is something in column A to compare
If .Cells(lngRow, "A").Value2 <> vbNullString Then
'This is the actual MATCH / FIND
Set rngFound = .Range("C:C").Find(What:=.Cells(lngRow, "A").Value2, LookIn:=xlValues, LookAt:=xlWhole)
'Evaluate the result of the FIND = rngFound
If rngFound Is Nothing Then
.Cells(lngRow, 2).Value2 = "Not in Stock" 'not found
Else
.Cells(lngRow, 2).Value2 = "In stock in row " & rngFound.Row 'found
End If
End If
Next lngRow
End With
End Sub
Let me know if you have and problems / questions.

Merge empty cells with previous value

I have an Excel file with around 100,000 records. I have 6+ columns, the first five of which are:
Required Format:
So far I have :
Sub Main()
Dim i As Long
Dim j As Long
Dim sameRows As Boolean
sameRows = True
For i = 1 To Range("A" & Rows.Count).End(xlUp).Row
For j = 1 To 4
If StrComp(Cells(i, j), Cells(i + 1, j), vbTextCompare) Then
sameRows = False
End If
Next j
If sameRows Then
Range(Cells(i, 4), Cells(i + 1, 4)).merge
End If
sameRows = True
Next i
End Sub
I am able to get below by running the macro by changing value in Range from 4 to 1/2/3/4 and running macro four times.
Please help me get the data in required format. I still need to merge the empty fields with the previous non empty field.
Pratik, listen carefully to Jeeped. Working with large data in Excel isn't ideal, and working with raw data in merged cells is staring into the abyss - it's a dark, dark place where Range referencing and things like Offset functions will show you a dimension of despair you never knew existed.
If you have this data in another format, say XML, that you've imported into Excel then use VBA to read the data, query it, etc. in its original format. If it exists in a database, then, again, use VBA to access that database and manipulate the recordsets as you wish. If this is your only source of data, then why not write it into an XML document or into VBA's own data storage options (like Collection or arrays).
If you have to use Excel then don't confuse raw data with data display. Yes, the merged cells might be easier to read for the human eye, but I'd just pose the question: is that your primary objective in conducting the merge?
If you must take that leap into the abyss - and you can see that at least two of us would advise against - then at least speed things up by reading from an array and merging rows at a time:
Sub OpenDoorsToHades()
Dim dataSheet As Worksheet
Dim v As Variant
Dim mergeCells As Range
Dim mergeAreas As Range
Dim i As Long
Dim blankStart As Long
Dim blankEnd As Long
Dim doMerge As Boolean
Dim c As Integer
Set dataSheet = ThisWorkbook.Worksheets("data") 'rename to your sheet
'Read values into array of variants
With dataSheet
v = .Range("A1", .Cells(.Rows.Count, "A").End(xlUp)).Value2
End With
'Check for blanks
For i = 1 To UBound(v, 1)
If IsEmpty(v(i, 1)) Then
If Not doMerge Then
blankStart = i - 1
doMerge = True
End If
Else
If doMerge Then
blankEnd = i - 1
For c = 1 To 4
With dataSheet
Set mergeCells = .Range( _
.Cells(blankStart, c), _
.Cells(blankEnd, c))
If mergeAreas Is Nothing Then
Set mergeAreas = mergeCells
Else
Set mergeAreas = .Range(mergeAreas.Address & _
"," & mergeCells.Address)
End If
End With
Next
mergeAreas.Merge
Set mergeAreas = Nothing
doMerge = False
End If
End If
Next
'Format the sheet
dataSheet.Cells.VerticalAlignment = xlCenter
Application.ScreenUpdating = True
End Sub
How about just populating the empty cells with the values above, so the values on the far right are associated with the same values that would've been in the merged cell. For example, if 19 is in cell A2, you can recreate the table starting in G2 with =IF(A2<>"",A2,G1), and this way all empty cells will be populated with the value above, pairing the values at the far right with the exact same values.
I tackled the same problem myself this week. Ambie's solution seemed overly complex, so I wrote something pretty simple to merge rows:
Sub MergeRows()
Sheets("Sheet1").Select
Dim lngStart As Long
Dim lngEnd As Long
Dim myRow As Long
'Disable popup alerts that appear when merging rows like this
Application.DisplayAlerts = False
lngStart = 2
lngEnd = 2
For myRow = 2 To Range("A" & Rows.Count).End(xlUp).Row 'last row
If Range("A" & (myRow + 1)).value = "" Then
'include row below in next merge
lngEnd = myRow + 1
Else
'merge if 2+ rows are included
If lngEnd - lngStart > 0 Then
Range("A" & lngStart & ":A" & lngEnd).Merge
Range("B" & lngStart & ":B" & lngEnd).Merge
Range("C" & lngStart & ":C" & lngEnd).Merge
Range("D" & lngStart & ":D" & lngEnd).Merge
End If
'reset included rows
lngStart = myRow + 1
lngEnd = myRow + 1
End If
Next myRow
Application.DisplayAlerts = True
End Sub

Loop through first row and if Cell Value = "Item Cost" then loop through that column and carry out subtotal in blanks

Very new to VBA but have managed to learn a lot in the last few weeks and stitch together some code for a project at work.
I am struggling with a loop within a loop.
Essentially I want to find every column in Row 1 that has cell value of "Item Cost" then loop down through each row in that column and place a subtotal in the blanks.
Any help with a solution would be greatly appreciated. It is part of a much larger project but I am at this sticking Point.
Code:
[VBA]
Sub InsertTotals()
Dim sh As Worksheet
Dim rw As Range
Dim RowCount As Integer
RowCount = 0
Set sh = ActiveSheet
For Each rw In sh.Rows
If sh.Cells(rw.Row, 1).Value = "Item Cost" Then
Dim ThisCell As Range
Dim MySum As Double
Set ThisCell = rw.offset(-1)
nxt:
Do While ThisCell <> ""
MySum = MySum + ThisCell
Set ThisCell = ThisCell.offset(1, 0)
Loop
ThisCell.Value = MySum
If ThisCell.offset(1, 0) <> "" Then
Set ThisCell = ThisCell.offset(1, 0)
MySum = 0
GoTo nxt
End If
End If
Next rw
End Sub
[VBA]
I've changed the way that the start and stop of the ranges to be subtotaled were collected. Additionally, every row has a subtotal at the bottom since there is likely an empty cell there.
Sub Insert_SubTotals()
Dim sh As Worksheet
Dim rw As Long, srw As Long, col As Long
Set sh = ActiveSheet
With sh
For col = 1 To Cells(1, Columns.Count).End(xlToLeft).Column
If .Cells(1, col) = "Item Cost" Then
srw = 2
For rw = 2 To .Cells(Rows.Count, col).End(xlUp).Row + 1
If IsEmpty(.Cells(rw, col)) And rw > srw Then
'.Cells(rw, col).Value = Application.Sum(.Range(.Cells(srw, col), .Cells(rw - 1, col)))
.Cells(rw, col).Formula = "=SUM(" & .Cells(srw, col).Address(0, 0) & _
Chr(58) & .Cells(rw - 1, col).Address(0, 0) & ")"
.Cells(rw, col).NumberFormat = _
"[color5]_($* #,##0.00_);[color9]_($* (#,##0.00);[color15]_("" - ""_);[color10]_(#_)"
srw = rw + 1
End If
Next rw
End If
Next col
End With
Set sh = Nothing
End Sub
I applied a blue Accounting style number format to distinguish the subtotals from the rest of the numbers. Modify that as you see fit. The subtotals remain as =SUM(...) formulas. I've added (and commented) a line that would simply leave the values just above the formula assignment.

Deleting rows in excel using VBA depending on values found using a formula [duplicate]

This question already has answers here:
Delete Row based on Search Key VBA
(3 answers)
Closed 8 years ago.
Hey guys I am trying to write a code that deletes rows having values that are found using a formula. The problem is every other row is a #VALUE!, which I cannot change due to the setup of the report. In the end I want to delete all rows that have #VALUE! and any row that has values that are less than .75 in Column H.
The code I tried is as shown below:
Private Sub CommandButton1_Click()
Dim rng As Range, cell As Range, del As Range
Set rng = Intersect(Range("H1:H2000"), ActiveSheet.UsedRange)
For Each cell In rng
If (cell.Value) < .75 Then
If del Is Nothing Then
Set del = cell
Else: Set del = Union(del, cell)
End If
End If
Next cell
On Error Resume Next
del.EntireRow.Delete
End Sub
Any help or tips would be appreciated.
I suggest stepping backwards through the rows so that when a row is deleted you don't lose your place.
Assuming that you want to look at cells contained in column H you could do something like this:
Sub Example()
Const H As Integer = 8
Dim row As Long
For row = ActiveSheet.UsedRange.Rows.Count To 1 Step -1
On Error Resume Next
If Cells(row, H).Value < 0.75 Then
Rows(row).Delete
End If
On Error GoTo 0
Next
End Sub
my code is an alternative to the other answers, its much more efficient and executes faster then deleting each row separately :) give it a go
Option Explicit
Sub DeleteEmptyRows()
Application.ScreenUpdating = False
Dim ws As Worksheet
Dim i&, lr&, rowsToDelete$, lookFor$, lookFor2$
'*!!!* set the condition for row deletion
lookFor = "#VALUE!"
lookFor2 = "0.75"
Set ws = ThisWorkbook.Sheets("Sheet1")
lr = ws.Range("H" & Rows.Count).End(xlUp).Row
ReDim arr(0)
For i = 1 To lr
If StrComp(CStr(ws.Range("H" & i).Text), lookFor, vbTextCompare) = 0 Or _
CDbl(ws.Range("H" & i).Value) < CDbl(lookFor2) Then
ReDim Preserve arr(UBound(arr) + 1)
arr(UBound(arr) - 1) = i
End If
Next i
If UBound(arr) > 0 Then
ReDim Preserve arr(UBound(arr) - 1)
For i = LBound(arr) To UBound(arr)
rowsToDelete = rowsToDelete & arr(i) & ":" & arr(i) & ","
Next i
ws.Range(Left(rowsToDelete, Len(rowsToDelete) - 1)).Delete Shift:=xlUp
Else
Application.ScreenUpdating = True
MsgBox "No more rows contain: " & lookFor & "or" & lookFor2 & ", therefore exiting"
Exit Sub
End If
If Not Application.ScreenUpdating Then Application.ScreenUpdating = True
Set ws = Nothing
End Sub
Try:
Private Sub CommandButton1_Click()
Dim rng As Range, cell As Range, del As Range, v As Variant
Set rng = Intersect(Range("H1:H2000"), ActiveSheet.UsedRange)
For Each cell In rng
v = cell.Text
If v < 0.75 Or v = "#VALUE!" Then
If del Is Nothing Then
Set del = cell
Else: Set del = Union(del, cell)
End If
End If
Next cell
On Error Resume Next
del.EntireRow.Delete
End Sub

Resources