I have a dataset of 40,000 rows of data. My code is set so that it checks if the date in row n+1 is 1 day after the date in row n. If the dates in rows n and n+1 do not follow in normal chronological order, then it adds a row with blank data for that date.
My issues is that because I am adding rows along as I go, I have no idea what the ending range my for loop should have. I also tried just setting a really large range like "For n = 2 to 50000". But this gives me an overflow error.
Here is my code:
Sub MissingDates()
Dim n As Integer
Worksheets("sheet1").Activate
For n = 2 To 40000
If Cells(n, 2).Value <> Cells(n + 1, 2).Value - 1 Then
Cells(n + 1, 2).EntireRow.Insert Shift:=xlShiftDown
Cells(n + 1, 2) = Cells(n, 2) + 1
End If
Next
End Sub
Thank you in advance for any help.
A signed integer does not reach 40,000 and you should work from the bottom up.
Option Explicit
Sub MissingDates()
Dim n As Long, m As Long
With Worksheets("sheet1")
For n = .Cells(.Rows.Count, "B").End(xlUp).Row - 1 To 2 Step -1
For m = .Cells(n + 1, "B").Value2 - 1 To .Cells(n, "B").Value2 + 1 Step -1
.Cells(n + 1, 2).EntireRow.Insert Shift:=xlShiftDown
.Cells(n + 1, 2) = m
Next m
Next n
End With
End Sub
The overflow error comes because you declare n As Integer (i.e. 32,767) but you push it until 40,000. You can solve that by declaring n As Long instead.
As for your problem, you rather want a While loop instead of a For one. It should look something like this:
n = 2 '<- your starting value
Do While Cells(n+1,2).Value <> "" '<-- I guess you stop when there's no more value in your row
If Cells(n, 2).Value <> Cells(n + 1, 2).Value - 1 Then
Cells(n + 1, 2).EntireRow.Insert Shift:=xlShiftDown
Cells(n + 1, 2) = Cells(n, 2) + 1
End If
n = n + 1 '<-- increment n
Loop
Related
I am trying to write a VBA Excel Macro to look through hundreds of thousands of lines of data to make sure that each unique entry in column A has a number of entries equal to column C.
For example:
Source Account Id 84512 occurs 6 times but there needs to be 12 occurrences (as indicated by column C). This means I need to add 6 lines, before (or after) the existing 6 lines.
Next we see Source Account Id 64857 occurs once but needs to occur 5 times. I would add 4 lines above and have the same Source Account Id code and the same Account Name. The rest of the cells can be "0".
Here is an example of the finished product:
Here is what I have so far:
Sub InsertRowAtChangeInValue()
Dim lRow As Long
Dim nMonths As Long
For lRow = Cells(Cells.Rows.count, "A").End(xlUp).Row To 2 Step -1
nMonths = 12 - Cells(Application.ActiveCell.Row, 3).Value
If Cells(lRow, "A") <> Cells(lRow - 1, "A") Then Rows(lRow).EntireRow.Resize(nMonths).Insert
Next lRow
End Sub
Please let me know if you have any suggestions.
*All data in these examples is fictional
Try this after renaming the referenced worksheet.
Sub expandMonths()
'https://stackoverflow.com/questions/52304181
Dim i As Long, j As Long, m As Long, a As Variant
With Worksheets("sheet1")
i = .Cells(.Rows.Count, "A").End(xlUp).Row
Do While i > 1
a = Array(.Cells(i, "A").Value2, .Cells(i, "B").Value2, 0, 0, 0, 0)
m = .Cells(i, "C").Value2
j = Application.Match(.Cells(i, "A").Value2, .Columns("A"), 0)
If i - j < m Then
.Rows(j).Resize(m - (i - j) - 1, 1).EntireRow.Insert
.Cells(j, "A").Resize(m - (i - j) - 1, UBound(a) + 1) = a
.Cells(j, "C").Resize(m - (i - j) - 1, 4).NumberFormat = "0"
End If
i = j - 1
Loop
End With
End Sub
Here is a reference image of my worksheet so that everyone can see the format.
http://imgur.com/a/dacIB
The purpose of this is to sort data that matches into columns. The criteria that I'm looking for is on the right and the database data that i'm looking through is on the left. Here is my code for the loop.
Dim i As Long
Dim Counter As Long
Dim WS_Count As Long
Dim k As Long
WS_Count = Worksheets.Count
For k = 4 To WS_Count
With Worksheets(k)
For Counter = 0 To ActiveSheet.Rows(1).Cells.Find("QQQ").Offset(0, -1) - 1
For i = 0 To ActiveSheet.Range("A" & ActiveSheet.Rows.Count).End(xlUp).Row - 2
If Cells(2 + i, 5).Value = Rows(i + 2).Cells.Find("QQQ").Offset(0, 1) And _
Cells(2 + i, 2).Value = Rows(i + 2).Cells.Find("QQQ").Offset(0, 3) And _
Cells(2 + i, 1).Value = Rows(i + 2).Cells.Find("QQQ").Offset(0, 2) Then
Cells(2 + i, Counter + 7).Value = Cells(2 + i, 4).Value
End If
Next i
Next Counter
End With
Next k
I need to get the Value in column D into columns associated with the criteria on the right. Columns G:O, numbered 1-9, match the column T numbers, 1-9.
I can't for the life of me figure out why, in Row 4, that it made 0's all the way across. It should go in this order all the rows in the first column > all the rows in the second column > ... > next sheet. If anything is unclear please let me know.
Edit: So my Counter and i Longs were slightly off so I made some adjustments. They should be right, but my code still isn't executing correctly. It is not seeing the matches it should. My If Then must be messed up some how.
Dim i As Long
Dim Counter As Long
Dim WS_Count As Long
Dim k As Long
WS_Count = Worksheets.Count
For k = 4 To WS_Count
With Worksheets(k)
For Counter = 0 To .Rows(1).Cells.Find("QQQ").Offset(0, -1).Value - 1
For i = 0 To .Range("A" & .Rows.Count).End(xlUp).Row - 2
If .Cells(2 + i, 5).Value = .Rows(Counter + 2).Cells.Find("QQQ").Offset(0, 1) And _
.Cells(2 + i, 2).Value = .Rows(Counter + 2).Cells.Find("QQQ").Offset(0, 3) And _
.Cells(2 + i, 1).Value = .Rows(Counter + 2).Cells.Find("QQQ").Offset(0, 2) Then
.Cells(2 + i, Counter + 7).Value = .Cells(2 + i, 4).Value
End If
Next i
Next Counter
End With
Next k
Okay, so it works now. I think it was having a really hard time figuring out what sheet to pull the statements from. Notice the .Cells(..... That period made the Cells defined to the ActiveSheet. I also changed .Rows(i+2)... to .Rows(Counter+2) The criteria cell location would shift down with each new imaking it impossible for there to be a match. The one in the screenshot just happened to be coincidence. Thanks, hope this helps someone in the future.
I'm trying to run a For Next Loop until the last row of a specific column (but not the last row of the sheet). So the first part of my list has data in column F and the second part doesn't. I only want the macro to apply to that first part. For some reason the loop only runs through the first part with certain commands but doesn't with the ones I am trying to do now. (I know it would be easy just to seperate the two parts manually and then run it but it drives me nuts not knowing what it is I did wrong :)).
This is the code:
Dim i As Integer
Dim g As Double
g = 0.083333333
Dim lastrow As Long
lastrow = Sheets("zm").Range("f" & Rows.Count).End(xlUp).Row
Sheets("zm").Activate
For i = 2 To lastrow
If Sheets("zm").Cells(i, 1) = Sheets("zm").Cells(i + 1, 1) And Sheets("zm").Cells(i, 5) = Sheets("zm").Cells(i + 1, 5) And Sheets("zm").Cells(i + 1, 6) - Sheets("zm").Cells(i, 7) < g Then
Sheets("zm").Cells(i + 1, 7).Copy
Sheets("zm").Cells(i, 7).Select
ActiveSheet.Paste
Application.CutCopyMode = False
Sheets("zm").Rows(i + 1).Delete
End If
Next i
Thanks for your help!
avoid Select/Selection and/or Activate/ActiveXXX
try this:
Option Explicit
Sub main()
Dim i As Long, lastrow As Long
Dim g As Double
g = 0.083333333
With Worksheets("zm")
lastrow = .Cells(.Rows.Count, "F").End(xlUp).Row
For i = lastrow To 2 Step -1
If .Cells(i, 1) = .Cells(i + 1, 1) And .Cells(i, 5) = .Cells(i + 1, 5) And .Cells(i + 1, 6) - .Cells(i, 7) < g Then
.Cells(i + 1, 7).Copy Destination:=.Cells(i, 7)
.Rows(i + 1).Delete
End If
Next i
End With
End Sub
I wrote a macro to insert a row between cells when their values are different. I have 9 columns in my data and the data starts at row 2. I want my macro to check all the values down column 3 (also known as column "C") and as it goes through, if the value changes (i.e. 2, 2, 2, 3, 3) it will insert a row between the changed value (i.e. 2, 2, 2, INSERT ROW, 3, 3). The problem is, my macro is reading column 5(E) not 3(C). What is wrong with it, I can't figure it out! The reason I know this too is because I placed a msgbox to spit the value of the cell and it matches everything in column 5 but not 3. Here is my code:
Sub Dividers()
Dim DividerRange As Range, lastrow As Long, k As Integer, counter As Integer
lastrow = Range("C2").End(xlDown).Row
Set DividerRange = Range(Cells(2, 3), Cells(lastrow, 3))
counter = 0
For k = 2 To DividerRange.Count
MsgBox DividerRange(k + counter, 3).Value
If DividerRange(k + counter, 3).Value = DividerRange(k + counter - 1, 3).Value Then
DividerRange(k + counter, 3).EntireRow.Insert
counter = counter + 1
Else
End If
Next k
End Sub
DividerRange(k + counter, 3).Value is a relative reference. DividerRange is a range starting at C2, so when you ask for the (i,j)th cell, i.e. (i,3) you get something from column E where jth columns would be: (C = 1, D = 2, E = 3)
You can simplify it quite a lot, there's no need for the Range or Range count, or counter:
Sub Dividers()
Dim lastrow As Long, k As Integer
lastrow = Range("C2").End(xlDown).Row
For k = 2 To lastrow
If Cells(k, 3).Value <> Cells(k - 1, 3).Value Then
Cells(k, 3).EntireRow.Insert
'Now skip a row so we don't compare against the new empty row
k = k + 1
End If
Next k
End Sub
I would appreciate some help on the following VBA Macro problem,
screenshot here:
I have to compare the data in 2 columns - Index & Sec_Index. In case of a match it should check which Values is assigned to the Sec_Index and fill a "1" to the matching Value column corresponding to Index and "0" for the other Value columns (I hope the screenshot explains it better)
I wrote a short macro which works good. However I have huge amounts of data - both Index columns contain at least 400000-500000 lines. This makes my code useless since it will take extreme long durations to execute.
Is there a way to make this work? I read about Variant arrays, but I'm not that familiar with them.
You can put this formula (if Excel 2007 or above):
=COUNTIFS($H$2:$H$5,$B2,$I$2:$I$5,"A")
into C2 and copy it down and across; just change "A" to "B" and "C".
Added In view of the number of rows, I would import the data into MS Access, create a Crosstab Query, then copy this data back to Excel.
Try this, not overly robust but does work. Not sure how quickly this will compare to what you may have had?
It did about 60,000 rows with 25 keys in about 5 seconds.
Edit: Added timer to function.
Public Declare Function GetTickCount Lib "kernel32.dll" () As Long
public Sub main()
Dim t As Long
t = GetTickCount
Application.ScreenUpdating = False
Dim Arr1(), Arr() As Double
Dim x, y, i, j As Double
Dim v As String
x = Cells(Rows.Count, 2).End(xlUp).Row - 2
y = Cells(Rows.Count, 8).End(xlUp).Row - 2
Range("c2", "e" & x + 2) = 0
ReDim Arr1(x)
ReDim Arr2(y)
i = 0
Do Until Cells(i + 2, 2) = ""
Arr1(i) = Cells(i + 2, 2)
i = i + 1
Loop
i = 0
Do Until Cells(i + 2, 8) = ""
Arr2(i) = Cells(i + 2, 2)
i = i + 1
Loop
i = 0
Do Until i > UBound(Arr1)
j = 0
Do Until j > UBound(Arr2)
If Arr1(i) = Arr2(j) Then
v = Cells(Arr2(j) + 1, 9)
Select Case v
Case "a"
Cells(i + 2, 3) = 1
Case "b"
Cells(i + 2, 4) = 1
Case "c"
Cells(i + 2, 5) = 1
End Select
Exit Do
End If
j = j + 1
Loop
i = i + 1
Loop
MsgBox GetTickCount - t, , "Milliseconds"
End Sub