How do I grab the string and adjacent number in multiple columns - vba

I want to run a loop to group the text by certain criteria and add up a total, but I need to be able to grab both bits of data.
Connecticut 624
Georgia 818
Washington 10
Arkansas 60
New Jersey 118
Ohio 2,797
The selection would be something like that, and I want the user to be able to highlight the two columns and I will run through and group the States by location and add the totals
edit--
So far, all I've been able to do is grab what the user selected range is:
Sub Short()
Dim rngMyRange As Range
If TypeName(Selection) = "Range" Then
Set rngMyRange = Selection
Else
Exit Sub 'Non-range type selection e.g. a chart
End If
MsgBox "The address of rngMyRange is " & rngMyRange.Address(False, False)
End Sub
I have a formula in another sheet that checks the states for their group, but it's one cell at a time
=IF( AND(D9="", B9="USA"),"",IF(B9="USA",IF(COUNTIF(Legends!$B$4:$B$13,D9)>0,"US Group 1",IF(COUNTIF(Legends!$F$4:$F$15,D9)>0,"US Group 3","US Group 2")),IF(COUNTIF(Legends!$H$4:$H$6,B9)>0,"Int'l Tier 1",IF(COUNTIF(Legends!$J$4:$J$15,B9)>0,"Int'l Tier 2","Int'l Tier 3"))))

Using the for loop below will loop through each cell in your range (selection - make sure you select just the column with the names in it)
Sub Short()
Dim rngMyRange As Range
Dim ttl as integer
Dim c
If TypeName(Selection) = "Range" Then
Set rngMyRange = Selection
Else
Exit Sub 'Non-range type selection e.g. a chart
End If
for each c in rngMyRange
ttl = ttl + c.offset(0,1)
next c
End Sub
You'll need to change the for loop with your criteria. This could be done a lot easier though by using a pivot table on your data range.

Related

Excel VBA Need to add comments to multiple cells depending on their value

I have a decent sized table, each cell depending on their value I want VBA to add a comment with the text I choose to show for each value.
For example: If value is 11 - the comment will show ACT Grid. Note values are sometimes integers and sometimes a combination of letters and numbers (A1, B1, C1, 1, 2, 3, etc)
11 ACT Grid
12 Device & Boarder Tile
13 CMHPII / USACE OH Sign-off
14 Drop Ceiling Tile
15 Trim Wall Devices
16 Install Casework
17 Install Flooring
18 Install Doors & Hardware
These are just a sample of the values in the table. Right now I have a command button that I'd like to have pressed to update the sheet each time it's pressed, that means remove any previous comments and replace with new. There will be many cells without any values and I'd like to make sure those don't have any comments. Here's my code, I had originally used ActiveCell but that only worked for the cell that I had previously selected. I'm sure my code looks empty since it's my latest compilation of attempted code. I'm not at all proficient in this language and looking for some help. Thanks!
Private Sub Update_Click()
Dim cell As Range
Dim rng As Range
Set rng = Range("D11:CY148")
On Error Resume Next
For Each cell In rng
If cell.Value = 50 Then
Target.AddComment
Target.Comment.Text Text:="test"
End If
Next cell
Application.EnableEvents = True
End Sub
An alternative to what you are trying to do is to use Case Statement. An example:
Private Sub Update_Click()
Dim cell As Range
Dim rng As Range
Set rng = Range("D11:CY148")
On Error Resume Next
For Each cell In rng
Select Case cell.Value
Case "11"
Target.AddComment
Target.Comment.Text Text:="ACT Grid"
Case "12"
Target.AddComment
Target.Comment.Text Text:="Device & Boarder Tile"
End Select
Next cell
Application.EnableEvents = True
End Sub

Excel VBA Code for small scroll while there is a value on the right

I have a Macro that takes data out of 2 reports.
in the second report I have dates that I copy. I need to take a date and subtract from it 14 days
I go to first blank cell in column D, then I want to calculate the formula in column C and scroll down without type how many cells (because it is a macro to a daily basis and the amount of data will change). I want to do this until the end of the data I copied.
In the end I want to copy it as values to column B.
Here is what I have in my code(part of all macro):
'first we go to the buttom of the column
'for NOW - change manually the top of the range you paste to
'Now, paste to OP_wb workbook:
OP_wb.Sheets("Optic Main").Range("D1").End(xlDown).Offset(1, 0).PasteSpecial
Paste:=xlPasteValues
' Calculate Due Date to MFG tools
' it means date we copied from MFG daily minus 14 days
_wb.Sheets("Optic Main").Activate
Range("C1").End(xlDown).Offset(1, 0).Activate
ActiveCell.FormulaR1C1 = "=RC[1]-14"enter code here
You need to loop from the first row to the last row. In general, there are plenty of good ways to define the last row of a given column. Once you have done it, replace the value of lngEndRow and run the following code:
Option Explicit
Public Sub TestMe()
Dim lngStartRow As Long: lngStartRow = 1
Dim lngEndRow As Long: lngEndRow = 100
Dim rngMyRange As Range
Dim rngMyCell As Range
With ActiveSheet
Set rngMyRange = .Range(.Cells(lngStartRow, 5), .Cells(lngEndRow, 5))
End With
For Each rngMyCell In rngMyRange
rngMyCell.FormulaR1C1 = "=RC[1]-14"
Next rngMyCell
End Sub
Then change the ActiveSheet with the correct sheet and the column hardcoded as 5 with the correct one. Run the code above in an empty Excel, to understand what it does. Then change it a bit, until it matches your needs.

Creating Macro for Copying data from one sheet to another,calculating the difference between dates in excel

The below mentioned data is for door access in a company where in we need to find the number of hours spent by a employee in office.
A employee can come in the office and swipe in and swipe out multiple times and all these details are register in the excel in non sorted order for all the employees.
I have a excel containing multiple columns
First two columns A,B are merged cells having date in this format(2015/01/25 7:27:30 PM).
The third column C has Access information having multiple entries for the below values(Entry/Exit).
For example
Column A Column B Access Employee ID Employee Name
==================================================
1. 2015/01/25 7:27:30 AM Entry 111 XYZ
2. 2015/01/25 7:30:30 AM Entry 333 ABC
3. 2015/01/25 8:30:30 AM Exit 111 XYZ
4. 2015/01/25 9:30:30 AM Entry 111 XYZ
5. 2015/01/25 9:30:30 AM Entry 444 PQR
6. 2015/01/25 10:30:30 Pm Exit 333 ABC
7. 2015/01/26 7:30:30 AM Exit 333 ABC
And so on.
Please note that the same employee can have multiple swipe in and out's throughout the day and will be clobbered among other employees information
The Goal is to as below
1) Copy the data from one sheet to another for the employees having spent time less than 9 hours for a specific day.
Here is the sample code that i have written it is work in progress
Sub HoursList()
Dim cell As Range
Dim cell1 As Range
Dim NewRange As Range
Dim NewRange1 As Range
Dim MyCount As Long
Dim ExistCount As Long
Dim ExistsCount As Boolean
Dim temp As Long
Dim MyCount1 As Long
Dim wsh As Worksheet, i As Long, lngEndRowInv As Long
Set wsh = Worksheets("Standard Door History ")
'Set cell = Range("A1")
ExistCount = 0
ExitsCount = False
MyCount = 1
MyCount1 = 1
i = 12
lngEndRowInv = wsh.Range("P" & wsh.Rows.Count).End(xlUp).Row
'----For every cell in row G on the Data sheet----'
For Each cell In wsh.Range("C12:D9085")
If cell.Value = "Entry" Then
'ExistCount = ExistCount + 1
If MyCount = 1 Then Set NewRange = cell.Offset(0, -1)
'----Sets up a new range to copy all data from the row if column in that row contains the value in question----'
Set NewRange = Application.Union(NewRange, cell.EntireRow)
MyCount = MyCount + 1
End If
Next cell
For Each cell1 In NewRange
If cell1.Value = "Mayur" Then
If MyCount1 = 1 Then Set NewRange1 = cell.Offset(0, -1)
'----Sets up a new range to copy all data from the row if column in that row contains the value in question----'
Set NewRange1 = Application.Union(NewRange1, cell.EntireRow)
MyCount1 = MyCount1 + 1
End If
Next cell1
If ExistCount > 0 Then
NewRange.Copy Destination:=Worksheets("Test").Range("A3")
End If
End Sub
Thanks
Here is a very rough version that you could use in VBA. It needs refining and error trapping, and future proofing, but it does what you want it to. It takes data from the active sheet and current adds it to the second worksheet. The date for looking up is in cell N1 of the first sheet.
Option Explicit
Sub CopyNine()
Dim LastRow As Integer
Dim DateToFind As Variant
Dim CellDate As Variant
Dim Count As Integer
Dim cel As Range
Dim DateRange As Range
Dim StaffID As String
Dim TimeStamp As Double
Dim StaffSummary As Object
Dim DS As Worksheet
Dim SS As Worksheet
Dim SSRow As Integer
LastRow = Range("A1").End(xlDown).Row
'You may wish to turn this into an input instead
DateToFind = Range("N1").Formula
Set DS = ActiveSheet
'You may wish to change this
Set SS = Sheets(2)
SSRow = 2
'Get a range containing all the correctly dated cells from the dataset
For Each cel In Range("A2:A" & LastRow).Cells
CellDate = Left(cel.Formula, InStr(1, cel.Formula, ".") - 1)
If CellDate = DateToFind Then
If DateRange Is Nothing Then
Set DateRange = cel
Else
Set DateRange = Union(DateRange, cel)
End If
End If
Next
'Create a summary dictionary of all staff IDs and their time spent in the office where 1 = 1 day
Set StaffSummary = CreateObject("scripting.dictionary")
For Each cel In DateRange.Cells
StaffID = cel.Offset(0, 3).Value
'These may need to be updated depending on your entry in the 'Entry/Exit' column
If cel.Offset(0, 2).Value = "Entry" Then
TimeStamp = -cel.Formula
Else
TimeStamp = cel.Formula
End If
If Not StaffSummary.exists(StaffID) Then
StaffSummary.Add StaffID, TimeStamp
Else
StaffSummary.Item(StaffID) = StaffSummary.Item(StaffID) + TimeStamp
End If
Next
'Copy the titles from the data sheet
SS.Range("A1:E1").Value = DS.Range("A1:E1").Value
'Copy the appropriate rows across using the dictionary you created
For Each cel In DateRange.Cells
StaffID = cel.Offset(0, 3).Value
If StaffSummary.Item(StaffID) <= 9 / 24 Then 'This is 9 hours so copy across
SS.Range("A" & SSRow & ":E" & SSRow).Value = DS.Range(cel, cel.Offset(0, 4)).Value
SSRow = SSRow + 1
End If
Next
End Sub
I would suggest using Excel's inbuilt abilities before VBA, especially if you are new to VBA. This will involve adding additional columns to your input sheet though which you can hide, but may not be ideal for your situation. It could also get quite slow as there are some large calculations, but it does depend on your original data set.
I would suggest the following (although there will be a lot of variations on it!):
1) Create a summary table for the particular day.
Create a date column in column F which is =TRUNC(A2) and copy down the table.
In M1 have your input date - e.g. 2015/01/25
In column L list all the unique Staff IDs
Below the date in M, use a SUMIFS formula and time formatting to determine how many hours each person spent. In M3 for example =SUMIFS($A:$A,$D:$D,$L2,$C:$C,"Exit",$F:$F,$M$1) - SUMIFS($A:$A,$D:$D,$L2,$C:$C,"Entry",$F:$F,$M$1) then formatting as hh:mm:ss.
In column N, use =M2<TIME(9,0,0) and drag down to work out if that individual has spent less than 9 hours in the building on that day.
You should now have a table showing all the staff and how many hours they spent in the building on that day, and a TRUE or FALSE whether they spent less than 9 hours.
2) Create your additional columns to pull the data to another sheet
In Column G, determine whether the entry is for the date in question (in cell M1) using =F2=$M$1 (should give a TRUE or FALSE)
In Column H, determine if that individual has spent less than 9 hours (from the summary table) using =INDEX(N:N, MATCH(D2, L:L,0))
In Column I, determine whether that entry should be copied across using =AND(G2, H2)
Finally in Column J, determine which entry this is to copy across using `=IF(I2, COUNTIFS($I$1:I2,TRUE),"")
Copy each of these down to the bottom of the table (you can hide them later)
3) Create your table on the next sheet for copying down - I have called my original worksheet "Data" and my second one "Copy"
In column A, use =ROW()-1 to create a sequential list of numbers
In column B, use =MATCH(A2, Data!J:J,0) to find out which row of data from the original table is being copied across
In column C, use =IFERROR(INDEX(Data!A:A,$B2),"") to pull the data from the first column
Copy this formula across to column G
Copy all of these down the sheet to however many rows of data you would like
Hide columns A, B and D since these will contain irrelevant information
You should then have an autoupdating table based on the date in cell M1 on the original data sheet. As mentioned above, this can be adapted in many ways, and it may not be ideal for your situation depending on your data set size, but it may be a start for you. If it is not suitable, then please use the theory to adapt some VBA code, as this can also be done in VBA in a very similar way.

Excel Find & Replace Macro

I have a worksheet which imports all of my orders, however when creating labels, I only have a limited amount of space for the title. I'm using a Find & Replace Macro in Excel which looks in my current active imported worksheet, and replaces with text from another worksheet which I use as a table with 2 columns, Column A is what the title is when imported and Column B is what I want to change it to. This script works perfectly fine except it doesn't find columns that have a different beginning. For example:
Imported Worksheet:
Entry 1: BANANAS
Entry 2: 30 X BANANAS
Table:
Column A: BANANAS
Column B: Yellow Bananas
//Script Runs//
Output:
Imported Worksheet:
Entry 1: Yellow Bananas
Entry 2: 30 X BANANAS
As you can see in the example above, the "30 X BANANAS" entry does not change to "30 X Yellow Bananas", as I would want it to. I'm guessing I need to add a wildcard line of code to my script below, but I'm not sure how to incorporate it?
Sub FindReplace()
Dim s As String
Dim cell As Range
For Each cell In Range("H3:H5000").Cells
If cell <> "" Then
ans = Application.VLookup(cell, Sheets("Script").Range("A1:B1000"), 2, 0)
If Not IsError(ans) Then cell = ans
End If
Next cell
End Sub
If you use the Range.Replace function rather than the VLookup function, you will get the result you are looking for.
Before
After
Sub FindNReplace()
Dim InputRng As Range, ReplaceRng As Range
'Set Range Values
Set InputRng = Range("A1:A5")
Set ReplaceRng = Sheets("Script").Range("A1:B100")
'Spin through replacement range and perform replace
For Each Rng In ReplaceRng.Columns(1).Cells
InputRng.Replace what:=Rng.Value, replacement:=Rng.Offset(0, 1).Value
Next
End Sub

Excel Macro: Selecting a specific Row based on column date

I am writing my first macro and have a question on how I can select a specific Row based on a value in a specific column. here is my code so far:
Sub Pipeline()
'Module 3
'Iterating through the Funding Date Column and looking for clients going live within 30 days
'Selecting the rows for each client in that target range
'TODO: Export information into an email template in Outlook
'TODO: Send email to distribution list
Dim fundingDate As range
Set fundingDate = range("M4:M500")
Dim todaysDate As Date
todaysDate = Date
For Each cell In fundingDate
If cell < todaysDate + 30 Then
'Need to select the entire row
Else
cell.Font.ColorIndex = 3
End If
Next
End Sub
replace 'Need to select the entire row with
cell.entirerow.select
UPDATE
Here is a much more efficient way to get what you need without all the looping.
In your code Replace from For Each cell ... to Next with this:
With fundingDate
.AutoFilter 1, "<" & todaysDate + 30
.SpecialCells(xlCellTypeVisible).Select
'here are your clients going live in next 30 days
.AutoFilterMode = False
End With
You may need to provide some error checking in case you don't have clients going live within 30 days (SpecialCells method will fail on this) and also, if M4 is not your column header, you may want to adjust how the range picks up the visible cells.