Excel VBA DO loop to scan range of dates and fill in missing dates - date

I have a worksheet that has ~20,000 rows of data. Each row has a Transaction Date in Column C. Each worksheet will only include data from the previous month. What I am trying to have happen, is to have a loop run through each date and make sure there are no missing dates, if there is a missing date, I need the loop to insert the missing date into a new row. I have found this online and have tried to customize it to my worksheet but cannot get it to work:
Dim i As Long: i = 1
'Adds missing dates as new rows
Do
If Cells(i + 1, "C") > Cells(i, "C") + 1 Then
Rows(i + 1).Insert xlShiftDown
Cells(i + 1, "C") = Cells(i, "C") + 1
End If
i = i + 1
Loop Until Cells(i + 1, "C") = ""
I have a bunch of different macros that format the data into a table and then sort it by the transaction date. I'm not sure if the table creates another issue or not but I can't seem to get it to work.
Any tips are greatly appreciated!

Starting with data that looks like this:
Run this code to loop through the dates bottom up and insert missing rows.
Sub insertMissingDate()
Dim wks As Worksheet
Set wks = Worksheets("Sheet1")
Dim lastRow As Long
lastRow = wks.Range("C2").End(xlDown).Row
'Work bottom up since we are inserting new rows
For i = lastRow To 3 Step -1
curcell = wks.Cells(i, 3).Value
prevcell = wks.Cells(i - 1, 3).Value
'Using a loop here allows us to bridge a gap of multiple missing dates
Do Until curcell - 1 = prevcell Or curcell = prevcell
'Insert new row
wks.Rows(i).Insert xlShiftDown
'Insert missing date into new row
curcell = wks.Cells(i + 1, 3) - 1
wks.Cells(i, 3).Value = curcell
Loop
Next i
End Sub
Results:

A note to anyone using this code- you have to have your date formatted so that in single digit months, (i.e. January- example "1/1/17") you have a zero in front of the month, making it two digit (i.e. 01/1/17). The code will not work unless you do this. There is a data type under "more data formats" on the home page of excel that will include zeros in front of a single digit month. Thanks for the code, it's helping me tremendously!

Related

VBA Autofilter subset contains extra row up top

The macro attempts to filter Sheet "Temp" for one Criteria at a time (PE, AR, DC,FI), and copy column 5 that contains non-duplicate data into another sheet "Detail". Please help me understand two issues. (1) The macro does correct filtering for each of the 4 criteria. However, the filtered list for each of the criteria always contains the first item from the filtered list of the very first criteria "PE". I.e. the filtered list for criteria 2, "AR", contains all items in AR, but starts with the first item in "PE". There's a header row, but it doesn't seem to make a difference. How can I get rid of that first item in all cases except when filtering for "PE" (where it belongs)? (2) I would like to be able to count and store the number of visible rows for each filtered list. I would like to be able to paste each filtered list into another spreadsheet ("Detail"), starting in cell A4. Each consecutive list should start two rows below the list that was just pasted. For example, if the first list contains 16 items, then the next list should start in cell A22 (A4+16+2). For some reason, copiedrows (used to remember number of rows in a filtered list) is correct the first time around (=16), but not the second time (=1?). It looks like q's 1 & 2 are related. Perhaps, if I figure out #1, I can do something about #2. I reviewed exiting posts on Autofiltering, but still feel a bit stuck here. Really appreciate your help!
Sub FilterCategories()
Dim LastRow As Long
Dim startpos As Integer
Dim k As Integer
Dim copiedrows(1 To 4) As Long
Dim AG(1 To 4) As String
Dim rng As Range
AG(1) = "PE"
AG(2) = "AR"
AG(3) = "DC"
AG(4) = "FI"
'Autofilter based on each AG and copy over to 'Detail'. Create temporary
sheet for filtering.
startpos = 4
For k = LBound(AG) To UBound(AG)
Application.DisplayAlerts = False
On Error Resume Next
Sheets("Temp").Delete
Sheets("Lookup").AutoFilterMode = False
Sheets("Lookup").Copy After:=Sheets("Lookup")
ActiveSheet.Name = "Temp"
With Sheets("Temp")
AutoFilterMode = False
LastRow = .Cells(.Rows.Count, "A").End(xlUp).Row
With .Range("A2:E" & LastRow)
.AutoFilter Field:=4, Criteria1:=AG(k)
.RemoveDuplicates Columns:=5
.Columns(5).SpecialCells(xlCellTypeVisible).Copy
Destination:=Sheets("Detail").Range("A" & startpos)
copiedrows(k) = .SpecialCells(xlCellTypeVisible).Rows.Count
Debug.Print copiedrows(k)
startpos = copiedrows(k) + 6
Debug.Print startpos
End With
End With
Next
End Sub

VBA Vlookup of range of dates in different sheets

I have zero coding experience and am new to VBA, so I don’t even know basics, but giving it a shot. I have a Workbook, with multiple sheet in it. The one that I care about are 2 sheets called DG, and Asp. DG has a button that grabs raw data from a server and populates the sheets ( multiple date columns with data value in adjacent cells). Asp has a button that grabs data as well but on a 30-day avg so every day in a month (columns A in Asp). This is the same case with DG sheet, but DG has data from different dates in a month, because it is not a 30 day pull. So that sets an image for you, now what I want to do is create a button, with a code that can go through a date column in DG and match it with a date from asp date and if there is a match, then copy and paste the adjacent cells values in DG to asp.
This is what I have so far with searches on the internet, showing just a vlookup for a single columns I want filled out in Asp, but its not working
Private Sub CommandButton2_Click()
Dim results As Double
Dim ws1 As Worksheet
Dim ws2 As Worksheet
Dim lrow As Long
Dim i As Long
Set ws1 = Worksheets("DG")
Set ws2 = Worksheets("Asp")
lrow = Worksheets("Asp").Range("A5", ws2.Range("A5").End(xlUp)).Rows.Count
For i = 5 To lrow
On Error Resume Next
result = Application.WorksheetFunction.VLookup((ws2.Range("A5" & i)), (ws1.Range("A11:B200")), 2, True)
ws2.Range("AG5").Value = result
If Err.Number = 0 Then
End If
On Error GoTo 0
Next i
End Sub
DG [1]: https://i.stack.imgur.com/ZrwfZ.jpg
ASP [2]: https://i.stack.imgur.com/tTsl0.jpg
It's Friday, Here you go, something to look at and study.
I am sorry I didn't use Vlookup, I have spent too much time chasing ghosts with that.
Perhaps others have had better success, I think what I don't like is Vlookup if it fails an exact match sometimes it chooses an adjacent row and throws everything into turmoil.
Here it is:
Option Explicit
Private Sub CommandButton2_Click()
Dim ws1 As Worksheet
Dim ws2 As Worksheet
Dim lrow2 As Long
Dim lrow1 As Long
Dim firstDataRow As Double
Dim matchRange As Range
Dim matchRow As Long
Dim i As Long
'Set up your Worksheet variables
Set ws1 = ThisWorkbook.Worksheets("DG")
Set ws2 = ThisWorkbook.Worksheets("Asp")
'You used A5 several times, so I will assume dates are in Col A and start at row 5
'Set your row with first data, maybe you need two, if they are the same on both sheets you don't
firstDataRow = 5
'find the last row on each sheet, using column A, the date col
lrow1 = ws1.Cells(ws1.Rows.Count, "A").End(xlUp).Row
lrow2 = ws2.Cells(ws2.Rows.Count, "A").End(xlUp).Row
'In your mind you now have two data ranges, one for each sheet, rows 5-last dat rows
'Pick one sheet, the one with less dates would be more efficient, you mention DG has less
'So this might be built backwards from what you are thinking, since we are iterating each row in the col
'You want to use the shrter call, IF you know its shorter (your comments)
'Loop through each row trying to find a match on your other sheet
For i = firstDataRow To lrow1
If ws1.Cells(i, "A") <> "" Then 'Test for empty
'Here is the premise of Find/Match over Vlookup
Set matchRange = ws2.Range("A" & firstDataRow & ":A" & lrow2).Find(ws1.Cells(i, "A"))
On Error Resume Next
matchRow = matchRange.Row 'Returns row number or nothing
If (Not matchRange Is Nothing) Then
'we have a row number matched on Asp, for our search item on DG
'perform the "Copy", this can be done differently but here I am going to introduce you to a way
'that can later be used with offsets and col #s, so that you may skip columns, data is not always adjacent
ws2.Cells(matchRow, "E") = ws1.Cells(i, "B")
ws2.Cells(matchRow, "F") = ws1.Cells(i, "C")
ws2.Cells(matchRow, "G") = ws1.Cells(i, "D")
Else 'DO NOTHING
End If
Else 'DO NOTHING
End If
Next i
MsgBox "Search and Copy is complete.", vbInformation, "Completed"
End Sub
There is so much more to talk about in even this simple project to make this more bullet proof. But this is a good start for where you are at.
Cheers! Happy Coding! - WWC

how to select multiple cells using offset variable but keeping what is in top 2 rows selected

I want to multi select cell on a worksheet. I might start with selecting a2:g22 but next time I want to select a2:g2 and offset the remaining rows by 20 so they will become a23:g23. The offset will have a variable which will have 20 added to it each time the code runs.
NextRow = Range("ba2")
NextRow = NextRow + 20
Range("a2:g2,a3:g22").Offset(NextRow, 0).Select
If nextrow = 0 then range a2:g2 is selected and a3:g22 is selected then I add 20 to nextrow and I want a2:g2 to be selected and a23:g42 selected.
What I get instead is a22:g22 selected and a23:g42 selected.
After doing something else for a few hours I realized that offset will always work with the entire range whatever that might be. So I tried replacing the cell references in the range with a variable with only partial success. If I have a variable called SelRow and I put in it the cell references Will that work. So that code looked like this:
SelRow = "A23:G42"
Range("A2:G2",SelRow).Select
This didn't work because my selection was A2:G42 so I changed it to this:
SelRow = "A2:G2,A23:G42"
Range(SelRow).Select
And that worked. So all I needed to do was to start with a reference number that was used to calculate 2 more variables called StRow and EndRowThe reference number can and will be anything but for now I started with 23.
StRow=23
EndRow = StRow + 19
NowSel = "a2:G2,A" & StRow & ":G" & EndRow
Range(NowSel).Select
That worked. The result of NowSelin this case was A2:G2,A23:G42This can of course get quite long so my final code looks like this:
StRow = Worksheets("Cell List").Range("A1") 'Get the last row number used
StRow = StRow + 20 'Set the next start row to last row + 20
EndRow = StRow + 19 'Set the last row for selection to start row + 19
NowSel = "a2:c2,f2:g2,a" & StRow & ":c" & EndRow & ",f" & StRow & ":g" & EndRow
Range(NowSel).Select
And now the following cells are selected A2:C2and F2:G2 and A23:C42and F23:G42
Now I can create charts just by changing a reference number.

Trying to build Expression for Table field to sort text dates, some with missing elements

Hi I am a newbie and have a problem I have been trying to solve for weeks. I have a table imported from excel with dates in text format (because dates go back to 1700s) Most are in the format "mmmyyyy", so it is relatively easy to add "1" to the date, convert to date format, and sort in correct date order. The problem I have is that some of the dates in the table are simply "yyyy", and some are empty. I cannot find an expression that works to convert these last two to eg 1 Jan yyyy and 1 Jan 1000 within the same expression. Is this possible, or would I need to do this in two queries? Sorry if this question is very basic - I cannot find an answer anywhere.
TIA
You can do something like:
Public Function ConvertDate(Byval Expression As Variant) As Date
Dim Result As Date
If IsNull(Expression) Then
Result = DateSerial(1000, 1, 1)
ElseIf Len(Expression) = 4 Then
Result = DateSerial(Expression, 1, 1)
Else
Result = DateValue(Right(Expression, 4) & "/" & Left(Expression, 3) & "/1")
End If
ConvertDate = Result
End Function

sum two values from different datasets using lookups in report builder

I have a report that should read values from 2 dataset by Currency:
Dataset1: Production Total
Dataset2: Net Total
Ive tried to use:
Lookup(Fields!Currency_Type.Value,
Fields!Currency_Type1.Value,
Fields!Gross_Premium_Amount.Value,
"DataSet2")
This returns only the first amount from dataset 2.
I've tried Lookupset function as well but it didn't SUM the retrieved values.
Any help would be appreciated.
Thanks Jamie for the reply.
THis is what i have done and it worked perfect:
From Report Properties--> Code , write the below function:
Function SumLookup(ByVal items As Object()) As Decimal
If items Is Nothing Then
Return Nothing
End If
Dim suma As Decimal = New Decimal()
Dim ct as Integer = New Integer()
suma = 0
ct = 0
For Each item As Object In items
suma += Convert.ToDecimal(item)
Next
If (ct = 0) Then return 0 else return suma
End Function
Then you can call the function:
code.SumLookup(LookupSet(Fields!Currency_Type.Value, Fields!Currency_Type1.Value,Fields!Gross_Premium_Amount.Value, "DataSet2"))
Yes, Lookup will only return the first matching value. Three options come to mind:
Change your query, so that you only need to get one value: use a GROUP BY and SUM(...) to combine your two rows in the query. If you are using this query other places, then make a copy and change that.
Is there some difference in the rows? Such as one is for last year and one is for this year? If so, create an artificial lookup key and lookup the two values separately:
=Lookup(Fields!Currency_Type.Value & ","
& YEAR(DATEADD(DateInterval.Year,-1,today())),
Fields!Currency_Type1.Value & ","
& Fields!Year.Value,
Fields!Gross_Premium_Amount.Value,
"DataSet2")
+
Lookup(Fields!Currency_Type.Value & ","
& YEAR(today()),
Fields!Currency_Type1.Value & ","
& Fields!Year.Value,
Fields!Gross_Premium_Amount.Value,
"DataSet2")
Use the LookupSet function as mentioned. With this you'll get a collection of the values back, and then need to add those together. The easiest way to do this is with embedded code in the report. Add this function to the report's code:
Function AddList(ByVal items As Object()) As Double
If items Is Nothing Then
Return 0
End If
Dim Total as Double
Total = 0
For Each item As Object In items
Total = Total + CDbl(item)
Next
Return Total
End Function
Now call that with:
=Code.AddList(LookupSet(Fields!Currency_Type.Value,
Fields!Currency_Type1.Value,
Fields!Gross_Premium_Amount.Value,
"DataSet2"))
(Note: this code was not tested. I just composed it in the Stack Overflow edit window & I'm no fan of VB. But it should give you a good idea of what to do.)