Hi i am trying to create a macro that will loop through my worksheet and find a specific string of text. Once if has found that string i want it to look to the column next to it and if it says PoweredOn or PoweredOff then add 1 to a counter then display the number at the end.
in my excel i have column A as my virtual machines and in column B is the power state I have a loop setup to look for one virtual machine that is a template and is powered on but when i run my macro it prints it as 0 here is my code at the moment.
Dim POT As Integer
Dim POFFT As Integer
Sheets("tabvInfo").Select
Range("A2").Select
Do
If ActiveCell.Value = ("vCloud Cell Template") Then
If ActiveCell.Offset(0, 1).Value = ("PoweredOn") Then
POT = Selection.Cell.Count
Else
If ActiveCell.Offset(0, 1).Value = ("PoweredOff") Then
POFFT = Selection.Cell.Count
End If
End If
End If
ActiveCell.Offset(1, 0).Select
Loop Until IsEmpty(ActiveCell.Offset(1, 0))
MsgBox ("The number of powerered on VMs is " & POT)
MsgBox ("The number of powerered off VMs is " & POFFT)
Can anyone tell me why i am getting 0 as the result? I also need to make this look at other templates on my system while retaining the count of values would i need to create a do loop for each template or can i use an array to do this?
Try this instead
Sub Main()
Dim POT As Long
Dim POFFT As Long
Dim c As Range
For Each c In Sheets("tabvInfo").Range("A2:A" & Sheets("tabvInfo").Range("A" & Rows.Count).End(xlUp).Row)
If StrComp(c, "vCloud Cell Template", vbTextCompare) = 0 Then
If StrComp(c.Offset(0, 1), "PoweredOn", vbTextCompare) = 0 Then
POT = POT + 1
ElseIf StrComp(c.Offset(0, 1), "PoweredOff", vbTextCompare) = 0 Then
POFFT = POFFT + 1
End If
End If
Next
MsgBox ("The number of powerered on VMs is " & POT)
MsgBox ("The number of powerered off VMs is " & POFFT)
End Sub
It eliminates the .Select statement and .ActiveCell. It's a simple for loop that achieves what you want.
I am not sure you realize but you can achieve this using 2 very simple formulas for PoweredOn and Off
=COUNTIFS(A:A,"vCloud Cell Template",B:B, "PoweredOn")
=COUNTIFS(A:A,"vCloud Cell Template",B:B, "PoweredOFF")
Therefore to eliminate the need for using a loop you can
Sub NoLoop()
MsgBox "Powered ON: " & Evaluate("=COUNTIFS(A:A,""vCloud Cell Template"",B:B, ""PoweredOn"")")
MsgBox "Powered OFF: " & Evaluate("=COUNTIFS(A:A,""vCloud Cell Template"",B:B, ""PoweredOff"")")
End Sub
Related
I want to use the .find function in VBA to find instances of a value in a column, however there are calculations which are made based on criteria on the same rows as where the value is found. This is problematic because although the value I am looking for might be the same, the criteria which are used to create the overall score are different. As a result, I would need to loop through all the values which are found in the column and I was wondering how to do that in vba. I know the findnext function but I can never get it to work properly.
counted = Application.WorksheetFunction.CountIfs(cl.Range(finletter & "9:" & finletter & "317"), "Value", cl.Range("H9:H317"), wl.Range("A" & y.row).Value)
'Pol small low complex
If counted > 0 Then
MsgBox wl.Range("A" & y.row).Value
If cl.Range("C" & y.row).Value < 3 And cl.Range("D" & y.row).Value = 1 And cl.Range("E" & y.row).Value = "Interim" Then
wl.Range(y.Address) = 3.75 * counted
Here is an example. Say we are looking for the text "LOVE" in column A and process the data on those rows:
Option Base 1
Sub LookingForLove()
Dim s As String, rng As Range, WhichRows() As Long
Dim rFound As Range
ReDim WhichRows(1)
s = "LOVE"
Set rng = Range("A1:A25")
Set rFound = rng.Find(What:=s, After:=rng(1))
WhichRows(1) = rFound.Row
Do
Set rFound = rng.FindNext(After:=rFound)
If rFound.Row = WhichRows(1) Then Exit Do
ReDim Preserve WhichRows(UBound(WhichRows) + 1)
WhichRows(UBound(WhichRows)) = rFound.Row
Loop
msg = UBound(WhichRows) & vbCrLf & vbCrLf
For i = 1 To UBound(WhichRows)
msg = msg & WhichRows(i) & vbCrLf
Next i
MsgBox msg
End Sub
NOTE:
the Exit Do prevents looping forever
your code would continue by looping the elements of WhichRows() and processing the items on those rows.
your code could alternatively create a dynamic array of ranges or cell addresses.
Another alternative approach would be to use VBA to establish an AutoFilter and process the visible rows.
I had a piece of code commissioned earlier this week (cheaper to have an expert write it than for me to spend a week trying to!). However, when putting it use I've hit a bit of a snag.
The macro looks at a name on one excel worksheet, matches it to a list of names and associated ID numbers on a different worksheet, then inserts the ID on the first worksheet. This was all fine until I started using it on real data.
Here's some sample data (all of this information is in one cell...):
WARHOL*, Andy
PETO, John F
D3 GRECO, Emilio -20th C
HASELTINE, William Stanley
D3 DALI, Salvador
D3 SOSNO, Sacha
WEGMAN**, WILLIAM
One asterisk means it's a print, two a photograph, D3 a sculpture, and nothing a painting.
When I run the code with this data, it sees * as a wildcard, and so will always insert the ID of the first variation of the artist in the sheet. What I need is a way for the macro to not read it as a wildcard.
I did some research, and found that inserting ~ before * negates the wildcard properties. How would I make my code do this? I've discovered the main issue of having code written by someone else... You might not understand it!
Here is the code:
Public Sub match_data()
'ctrl+r
On Error GoTo errh
Application.ScreenUpdating = False
Application.Calculation = xlCalculationManual
Dim r1, r2, i, exc As Long
Dim fp As Range
Sheets("Data").Activate
r1 = Cells(Rows.Count, "B").End(xlUp).Row
r2 = Sheets("List").Cells(Sheets("List").Rows.Count, "B").End(xlUp).Row
'MsgBox r1 & r2
exc = 0
For i = 2 To r1
If Range("B" & i).Value <> "" Then
With Sheets("List").Range("B2:B" & r2)
Set fp = .Find(Range("B" & i).Value, LookIn:=xlValues, lookat:=xlWhole)
If Not fp Is Nothing Then
Range("B" & i).Interior.Color = xlNone
Range("A" & i).Value = Sheets("List").Range("A" & fp.Row).Value
Else
Range("B" & i).Interior.Color = xlNone
Range("B" & i).Interior.Color = vbYellow
exc = exc + 1
End If
End With
End If
Next i
MsgBox "There are " & exc & " exceptions."
errh:
If Err.Number > 0 Then
MsgBox Err.Description
End If
Application.ScreenUpdating = True
Application.Calculation = xlCalculationAutomatic
End Sub
Oh also, I would need to do this for the list of names and ID's wouldn't I? If so, that only needs doing once, so if you could give me a hint about that too, I'd be so grateful!
Thanks!
PS I know the system we are using at the moment absolutely sucks (definitely not 3rd form normalised!), but we are fast running out of time and money, and need to get our product up and running ASAP!
EDIT: To clarify, here is a pic of the spreadsheets I'm working with... Obviously in cells A14 and A15 I wanted the ID numbers 11 & 12 respectively
Here is one way to tell the stars from the planets:
Sub StaryNight()
Dim s As String, OneStar As String, TwoStar As String, ThreeStar As String
OneStar = "*"
TwoStar = "**"
ThreeStar = "***"
t = Range("A1").Text
ary = Split(t, ",")
s = ary(0)
If Right(s, 3) = ThreeStar Then
MsgBox "scupture"
Exit Sub
ElseIf Right(s, 2) = TwoStar Then
MsgBox "photograph"
Exit Sub
ElseIf Right(s, 1) = OneStar Then
MsgBox "print"
Exit Sub
End If
MsgBox "Painting"
End Sub
Okay, I have solved the problem! I had a play around with changing the variables in the Find and Replace box.
If I put ~* in both the find AND replace boxes, and uncheck Match entire cell contents, I can replace all of the * with ~* (really don't understand that but oh well!)
So I do this on the Data worksheet, but NOT on the List worksheet, run the macro as normal and the problem is solved!
I have two workbooks, and both shave a list of ALMOST the same items. One of the list has a few extra spaces at the end of its list and it's throwing me completely off.
Public Sub test() 'Imports data into M&R spreadsheet
Dim wbMnR As Workbook
Dim wbMatch As Workbook
Set wbMnR = Workbooks("MnRs.xlsx")
Set wbMatch = Workbooks("Match.xlsm")
Dim myRow As Integer
For i = 1 To 10
myRow = WorksheetFunction.Match(wbMatch.Worksheets(1).Range("a" & CStr(i)), wbMnR.Worksheets(1).Range("A:A"), 0)
Debug.Print myRow
Next i
End Sub
The item list in copy is
"R-01"
"R-02"
"R-03"
"R-04"
the item list in paste is
"R-01 "
"R-03"
"R-02"
"R-04 "
These are just examples I made up and for various reasons I can't input my actual data. I cannot sort my list in the MnR worksheet though since the workbook I was given contains some merge cells and various data which separates specific sections. With the way Match works, I know that using a perfect match of "0" will not work because of the extra space, but using a "1" or "-1" will not work either because my list cannot be sorted.
Try this Select Case statement.
With wbMatch.Worksheets(1)
For i = 1 To 10
myRow = 0
Select Case False
Case IsError(Application.Match(.Range("a" & i), wbMnR.Worksheets(1).Range("A:A"), 0))
myRow = Application.Match(.Range("a" & i), wbMnR.Worksheets(1).Range("A:A"), 0)
Case IsError(Application.Match(.Range("a" & i) & Chr(32), wbMnR.Worksheets(1).Range("A:A"), 0))
myRow = Application.Match(.Range("a" & i) & Chr(32), wbMnR.Worksheets(1).Range("A:A"), 0)
Case Else
'nothing found
End Select
Debug.Print myRow
Next i
End With
If you run into further trouble, that Select Case will be easier to expand upon. To make this more efficient, the most common matches should be at the top of the Case statements.
In the following picture of an Excel sheet, the heading of the first column, and then of every 7th column after that, contains a month and a year.
I am trying to think of some code which would make entering complete dates under these headings faster. Since the month and the year are already present, I'm thinking there must be a way to enter just the day, and get the whole thing. For example, if "21" were entered in cell A26, "2/21/2015" would result.
Anyone have an idea for how I might get this output?
Edit: Thanks to the helpful replies on this forum, I figured out exactly how to do this. Here is the code for my finished product, in case anyone wants to do something similar:
Private Sub Worksheet_change(ByVal Selection As Range)
Set Sel = Selection
If Sel.Count > 1 Then
Exit Sub
End If
If (Sel.Column - 1) Mod 7 = 0 Or Sel.Column = 1 Then
'In my case, date columns always follow the pattern of 1, 8, 15...
If Sel.Value > 31 Or Sel.Value = "" Then
Exit Sub
Else
Sel.NumberFormat = "General"
Sel.Value = Left(Cells(1, Sel.Column), InStr(Cells(1, Sel.Column), ",") - 1) & " " & _
Sel.Value & Right(Cells(1, Sel.Column), 6)
Selection.NumberFormat = "m/d/yyyy"
End If
End If
End Sub
How about entering the day numbers, selecting the range where these day numbers are entered, and running the below:
Sub Add_month_year()
Dim c As Range
For Each c In Selection
c = Left(Cells(1, c.Column), InStr(Cells(1, c.Column), ",") - 1) & " " & _
c.Value & Right(Cells(1, c.Column), 6)
Next
End Sub
This should return the full dates in date code, which you can then format as you see fit.
Why does the following code not delete irrelevant rows in my spreadsheet?
Sub Macro1Format()
'
' Macro1Format Macro
'
Dim i As Integer
i = 0
Do While (Range("A1").Value <> "Project ID") And (i < 100)
Range("1:1").Delete
i = i + 1
Loop
End Sub
I'll take a stab that you would like something like:
Sub Macro1Format()
Dim i As Integer
i = 99
For i = 99 To 1 Step -1
If Range("A" & i).Value <> "Project ID" Then
Range(i & ":" & i).Delete
End If
Next
End Sub
You seem to have confused 1 with i but also when deleting rows it may be best to start from the bottom up since the row count changes as a consequence of any row deletion. There were also some syntax problems.