I'm trying to help a colleague out with their spreadsheets (on MAC Excel V16.16.8), since I have some experience with coding, mostly in SQL, only very very basic level of VBA.
They receive daily data (which is why VBA is needed) which I have managed to split into separate sheets for them using basic macros.
The name of the sheet is "Birmingham" in this example.
Column B "Interval" are the hours of the day (24 hour clock). They only receive any data for the hours of the day where data actually exists in other columns. However, for their reports, they need to add/insert new rows even where there isn't any data from 0-23 (midnight-11pm).
The "Interval" column needs the correct hour/number in this descending order as seen in the example, with the Date and Campaign columns just being the same throughout. And have the rest of the cells for Total_Calls, Closed, etc, containing "0"s.
How do I add the new rows, "Intervals", and the "0"s?
I have tried a couple of different ways mostly around attempting to merge a mostly blank separate table only containing all of the "Intervals" 0-23. However, I have failed miserably in each method.
I am almost 100% sure there is a relatively simple method of doing this, but I lack specific VBA knowledge.
Any help would be most appreciated.
Thanks
You can get the current date and current campaign and insert missing rows like this:
Private Sub FillAllHours()
Dim i As Long
Dim myDate As Date ' value from date column
Dim myCampain As String ' value from campaign column
With ActiveSheet
myDate = .Cells(.Rows.Count, 1).End(xlUp).Value
myCampain = .Cells(.Rows.Count, 3).End(xlUp).Value
For i = 2 To 25
If .Cells(i, "B") <> i - 2 Then ' if row is missing
.Rows(i).Insert ' insert row above
.Cells(i, "B") = i - 2 ' insert hour number
.Cells(i, "A") = myDate ' insert date
.Cells(i, "C") = mycampaign ' insert campaign
.Cells(i, "D").Resize(1, 9).Value = 0 ' fill 9 cells with 0
End If
Next i
End With
End Sub
Related
I'm trying to create a macro that categorizes my bank statements. But I'm not that proficient with VBA and I don't have a clear idea on how to tackle this problem.
It goes as follows:
I import a CSV into excel which I delimit into columns. This part is working now. Looking like this:
I want to be able to cut the relevant transactions and paste them to their respective tables. So municipality goes to the municipality table, bank goes to the bank table, energy goes to the energy table.
I am using different banks so therefore I have different CSVs. So the layout changes all the time. Some banks have Date in column A, some in column C. So the ranges should always be dynamic.
I created a Key Table that has all the relevant variables that can match with the relevant transactions looking like this:
The Key can be found somewhere in the Imported range. Like I said before, the location of the key changes depending on the bank. I want to be able to say the following.
If key x matches somewhere in import_range then cut "Name, Description and Amount from the same row into another table on another worksheet which correlates to the Type of the Key.
So from the image, if key 21315665 is found (as a string?) somewhere in import_range then I want the Name (internet provider), Description and Amount that correlates to that same row cut and pasted into a different (already existing) table, adding the information to the bottom of said table.
I hope anyone can help me out with this. I have a working code that I wrote but it is a pain to update and very basic. It just compares if key x is in cell z and if so copies it.
Dim myString As String
Dim incassovalue As String
Dim lastrow As Range
Dim Table As ListObject
Set Table = Sheets("Transactions").ListObjects("Energy")
Import_last_row = Sheets("Import").Range("A" & Rows.Count).End(xlUp).Row
For i = Import_last_row To 6 Step -1
'Energy
myString = Sheets("Import").Cells(i, 9).Value
incassovalue = Sheets("Incasso").Cells(5, 5).Value
If InStr(myString, incassovalue) > 0 Then
If Table.ListRows.Count > 0 Then
Set lastrow = Table.ListRows(Table.ListRows.Count).Range
If Application.CountBlank(lastrow) < lastrow.Columns.Count Then
Table.ListRows.Add
End If
End If
If Table.ListRows.Count = 0 Then
Table.ListRows.Add Position:=1
Set lastrow = Table.ListRows(1).Range
Else
Set lastrow = Table.ListRows(Table.ListRows.Count).Range
End If
Sheets("Import").Cells(i, 1).Copy Table.Range([Energy].Rows.Count + 1, 1)
Sheets("Import").Cells(i, 2).Copy Table.Range([Energy].Rows.Count + 1, 2)
Sheets("Import").Cells(i, 7).Copy Table.Range([Energy].Rows.Count + 1, 3)
Sheets("Import").Cells(i, 1).EntireRow.Delete
End If
Next i
Now this code kind of works, but it isnt dynamic at all, I would have to make a 1000 conditions like this to make it work for all my bank accounts. I hope someone here can help me out, or send me in the right direction.
Say that I have a spreadsheet that allows users to put in some metadata like the following:
Date range start: mm/dd/yyyy
Date range end: mm/dd/yyyy
Mondays: (y/n)
Tuesdays: (y/n)
Wednesdays: (y/n)
Thursdays: (y/n)
Fridays: (y/n)
Based on that, I want to generate a list of dates in the format of mm/dd/yyyy that starts on 4/1/2019, ends on 4/30/2019 and only includes dates of the day that was indicated with a y.
So if a user put in start date = 04/01/2019, end date = 04/30/2019, y for just Mondays and Wednesdays, the list would look like:
04/01/2019
04/03/2019
04/08/2019
04/10/2019
04/15/2019
04/17/2019
04/22/2019
04/24/2019
04/29/2019
Couldn't find an Excel function to start with. I don't know VBA but imagine it would be possible to do this with that.
If I wanted to write this in Python by using an add-in like Pyxll, would everyone with a copy of the Excel file be required to install Pyxll?
#simplycoding: VBA doesn't have a function or suroutine ready to do what you are looking for right out of the box. However, you can compose your own ones based on whatever VBA has on offer, which is a lot.
This is my startup scenario:
I wrote, tested and commented the following SUB in some 20 minutes. Believe me when I say I'm not a first row VBA coder.
Sub DateList()
'(C) Antonio Rodulfo, 2019
Dim dEnd, dStart, dCounter As Date
Dim iaDays(1 To 5) As Integer
Dim iCounter, iRow As Integer
' Indent your sentences properly
' Reading parameters
dStart = Cells(2, 1).Value
dEnd = Cells(2, 2)
For iCounter = 1 To 5
If Cells(2, 2 + iCounter) = "y" Then
iaDays(iCounter) = 1
Else
iaDays(iCounter) = 0
End If
Next iCounter
' Here's where the list of dates will start
iRow = 4
' I process the dates: Excel stores dates in its own
' coding, which we can use to run a for..next loop
For dCounter = dStart To dEnd
' Weekday(datecode,type) returns the day of week
' type 2 means the week starts with monday being day 1
iCounter = Weekday(dCounter, 2)
' The sub only sets dates for working days
' monday to friday
If iCounter <= 5 Then
' date must be set if found "y" in the matching day
If iaDays(iCounter) = 1 Then
' I like setting the proper numberformat so
' that no surprises are found when reading it
Cells(iRow, 1).NumberFormat = "dd/mmm/yyyy"
Cells(iRow, 1) = dCounter
' Increasing iRow sets the focus on next row
iRow = iRow + 1
End If
End If
' Adding the index name to the next sentence helps
' tracking the structures
Next dCounter
End Sub
I always recommend using Option Explicit when coding. It can seem annoying at first, but it will help you a lot when testing and debugging your code.
Good luck!
I was challenged by your request to not use VBA at all, so I was playing around with some Excel functions and here's what I would like you to try.
I used your metadata in the following cells:
OPTION 1 - easy
Enter the following Array function into cell D1 (Ctrl+Shift+Enter) and drag it all the way to the right (e.g. up to cell AW1):
=IF(AND(ISNUMBER(MATCH(WEEKDAY($B$1+COLUMN()-4,2),--($B$3:$B$7="y")*(ROW($B$3:$B$7)-2),0)),($B$1+COLUMN()-4)<=$B$2),$B$1+COLUMN()-4,"")
All dates that are between Start & End dates and for the required weekdays are displayed. However, this option does not prevent the gaps, so you will have lots of blank columns in between.
OPTION 2 - complete
Enter the following Array function into cell D2 (Ctrl+Shift+Enter) and drag it all the way to the right:
=IFERROR(SUMPRODUCT(SMALL(($B$1+ROW($B$1:$B$30)-1)*(IF(ISNUMBER(MATCH(WEEKDAY($B$1+ROW($B$1:$B$30)-1,2),(--($B$3:$B$7="y")*(ROW($B$3:$B$7)-2)),0)),1,0)),30-COUNT(MATCH(WEEKDAY($B$1+ROW($B$1:$B$30)-1,2),(--($B$3:$B$7="y")*(ROW($B$3:$B$7)-2)),0))+COLUMN()-3)),"")
As you can see, this option displays all "proper" dates next to each other, without any gaps.
Hope you will find this helpful - I had lots of fun playing around with the second option and I'm sure it can be still improved.
Take care,
Justyna
I've got a problem with properly setting a VBA code in order to have excel unlocking for editing only cells of a specific column in a row based on a date in another column.
I've got a range of dates (advancing by a month) in column "A", and place for inserting data i.a. in column "I". On one hand, for the purpose of different column, I need all 12 months a year in column "A", while I wanted to allow user of the sheet to do entries in column "I" only in cells of a row where there is March in column "A". Each year up to the end of the list in column "A".
So far, I tried many different examples of code for similar cases, but none of them worked. It seems that most of my problem is with the proper definition of If in connection with Month or LMonth formula.
Below, one of codes I tried:
Private Sub Worksheet_Change(ByVal Target As Range)
Dim i As Integer
For i = 2 To 319
If Cells(i, 1).Month = "3" Then
Cells(i, 9).Locked = False
ElseIf Cells(i, 1).LMonth <> 3 Then
Cells(i, 9).Locked = True
End If
Next i
End Sub
After running such code, I receive
Runtime error '438': Object doesn't support this property or method
Spent so much time on that and still no results, so I would be really grateful for any help!
Many thanks in advance!
I am attempting to change sheet names while increasing selected dates by one (1) year.
OCT is the beginning of a new fiscal year (FY) and I'm trying to adjust accordingly. For example OCT-17, NOV-17, DEC-17, JAN-18, etc. I'm trying to change to OCT-18, NOV-18, DEC-18, JAN-19 in order to clear previous data and enter the new FY information.
Thus far, I have been able to adjust sheet names, however I am stumbling on being able to "select" the range of dates that I am attempting to adjust for the new FY. I am attempting to select the range of dates and add one (1) year to each of the dates in order to reference accurate data as the table references a pivot table as its data source.
Dim MyDate As String
Dim Cell as Range
MyDate=Format(DateSerial(Year(Date), Month(10), 1, "yy")
If FormMonth = "OCT" then
sheet1.name = "FY" & MYDate - 3
sheet1.range("B9:M9").select
For Each Cell in selection
cell.value = DateAdd("yyyy", 1, CDate(cell.value))
Next cell
End If
I have MyDate - 3 to change the sheet names as I have separate sheets that hold the previous 3 years of FY data. That successfully changes the year to the FY information I would like to present.
My script is not liking the sheet1.range("B9:M9").select.
You need to set sheet1 to a worksheet:
mySheetName = "FY" & MYDate - 3
Set sheet1 = Worksheets(mySheetName)
That said, you really want to avoid using Activate/Select in your code. Something like:
For Each Cell in sheet1.range("B9:M9")
cell.value = DateAdd("yyyy", 1, CDate(cell.value))
Next cell
So I have this file with 60K rows. My data analyst people need to go through this and pick out about 30K rows. This occurs every few days.
They have 1 sheet with the 60K rows, and they have another with the 30k rows to pull out. I put them together in one workbook. then what I did was write a macro that took all the values in the column they are using for finding the correct rows (It's column A, an ID column) and put those values in an array.
code:
'in this code the active sheet is the one with the 30k rows to pull
For i = 1 To numrows
killArray(index) = ActiveCell.Offset(i - 1, 0).value2 'did research and value2 is fastest
index = index + 1
Next
and then I used the autofilter:
'here the sheet with all 60k rows is active
Cells(1, IdCol).entireColumn.autofilter Field:=1, Criteria1:=Array(killArray), Operator:=xlFilterValues
So that then takes all 30k Id's puts them into an array, and filters the sheet with all rows using the array. Then the data guys can briefly look over it, and delete all of those rows.
now, they have decided they really want to use a custom format for the ID column. all id's are between 1 and 6 digits. so from 1 - 999999. the data guys have decided they like formatting it so that ALL id's are 6 digits, with leading 0's. so id 1 would be 000001.
the problem is when I use .value to put the id's into the kill array, it gets the id without formatting. so id 000001 would be just 1. this would be fine except the autofilter doesnt work now. because id - 1, does not match id - 000001. I've done some checking, and I found I could use killArray(index) = ActiveCell.Offset(i - 1, 0).text but during the course of my research (and testing) I've discovered this is VERY slow.
Is there a way to have autofilter ignore the formatting? I've done lots of reseach but I have only managed to find people having issues with dates. I don't have an issue with dates
You can probably get better performance with
killArray = application.transpose(some_range.value2)
for n = lbound(killarray) to ubound(killarray)
killarray(n) = Format(killarray(n), "000000")
next n
or even
Dim killArray
Dim somerange As Range
Set somerange = Range("A2:A10000")
With somerange
killArray = Application.Transpose(Evaluate("INDEX(TEXT(" & .Address & ",""000000""),)"))
End With
If you have a need for speed, first remove the un-necessary loop:
For i = 1 To numrows
killArray(Index) = ActiveCell.Offset(i - 1, 0).Value2
Next
This can be replaced by:
killArray(Index) = ActiveCell.Offset(numrows - 1, 0).Value2