Worksheet Change Event - check cells in column for % difference - excel

I am struggling to get a Worksheet_Change event to work with the goal of checking if there is a % difference greater than 10% between range G12:42 and range J12:42. I have a calculation in range G12:42, which seems to be causing me some of the headache.
Private Sub Worksheet_Change(ByVal Target As Range)
Dim diffPercent
'Check that the data is changed between row 12 and 42 and it is even row. eg 12,14,16...42.
If (Target.Row > 12 And Target.Row < 42) And ((Target.Row Mod 2) = 0) Then 'And _
'(Target.Column = 7 Or Target.Column = 10) Then
'Get the values in J ang G columns of that particular row.
number1 = Range("G" & Target.Row).Value
number2 = Range("J" & Target.Row).Value
'Check for presence of both the inputs to calculate difference in percentage.
If Not chkInputs(number1, number2) Then
Exit Sub
End If
'Calculate the percentage difference.
diff = number2 - number1
diffPercent = (diff / number2) * 100
'Give alert if difference more than 10 percent
If diffPercent > 10 Then
MsgBox "Oppps. Your system is not working!"
End If
End If
End Sub
Function chkInputs(number1, number2)
chkInputs = False
If IsNumeric(number1) And IsNumeric(number2) Then
chkInputs = True
End If
End Function
The expected result is the triggering of a MsgBox providing a message.

No need to have a separate funciton. You can include it in the main code. Also use Intersect to work with the relevant range else the code will trigger if there is a change anywhere in that row range. One more thing. Check if the cell in column J is not 0 else you will get an Overflow error.
You may also want to see Working with Worksheet_Change
Is this what you are trying (Untested)?
Option Explicit
Private Sub Worksheet_Change(ByVal Target As Range)
Dim rngToCheck As Range
Dim NumA As Variant, NumB As Variant
Dim i As Long
On Error GoTo Whoa
'~~> Set the relevant range
Set rngToCheck = Union(Range("G12:G42"), Range("J12:J42"))
Application.EnableEvents = False
If Not Intersect(Target, rngToCheck) Is Nothing Then
For i = 12 To 42 Step 2 '<~~ Loop through only even rows
NumA = Range("G" & i).Value
NumB = Range("J" & i).Value
If IsNumeric(NumA) And IsNumeric(NumB) And NumB <> 0 Then
If ((NumA - NumB) / NumB) * 100 > 10 Then
MsgBox "Please check the value of Col G and J Cells in row " & i
Exit For
End If
End If
Next i
End If
Letscontinue:
Application.EnableEvents = True
Exit Sub
Whoa:
MsgBox Err.Description
Resume Letscontinue
End Sub

Related

If column doesn't have any value greater than 1 then exit

I'm trying to create an IF statement that does the following:
highlights (with red color) anything with a value greater than 1 and less than 26, and then continue with the rest of the macro and do other things (which I've successfully done).
if there's a value over 25, then highlight with red, produce a messagebox, and exitsub (which I've successfully done).
if ALL rows are = 1, then do nothing and exit sub (which i'm struggling with).
For Each C In Range("B2:B25000").Cells
If C.Value > 1 And C.Value < 26 Then
firstValue = C.Value
firstAddress = C.Address
Exit For
If Not (C.Value > 1 And C.Value < 26) Then Exit Sub 'No
ElseIf C.Value > 25 Then
C.Interior.Color = VBA.ColorConstants.vbRed
MsgBox "Too big!"
Exit Sub
End If
Next
C.Interior.Color = VBA.ColorConstants.vbRed 'if greater than 1 & less than 26 then Color = red
'remaining of the macro goes here
End Sub
Use the if statements to set logic flags and then decide whether to exit sub or continue.
Option Explicit
Sub test()
Dim ws As Worksheet, c As Range, lastrow As Long
Dim bAllOnes As Boolean, bTooBig As Boolean
Set ws = Sheet1
bAllOnes = True
bTooBig = False
lastrow = ws.Cells(ws.Rows.Count, "B").End(xlUp).Row
For Each c In ws.Range("B2:B" & lastrow).Cells
If Val(c.Value) > 1 Then
bAllOnes = False
c.Interior.Color = VBA.ColorConstants.vbRed
If c.Value > 25 Then
bTooBig = True
End If
ElseIf Val(c.Value) < 1 Then
bAllOnes = False
End If
Next
If bTooBig Then
MsgBox "Too big!", vbCritical
Exit Sub
ElseIf bAllOnes Then
MsgBox "All 1's!", vbCritical
Exit Sub
Else
MsgBox "Continueing"
End If
End Sub
I replaced this
If Not (C.Value > 1 And C.Value < 26) Then Exit Sub
with this ElseIf Application.WorksheetFunction.max(Range("b:b")) = 1 Then Exit Sub
and it worked perfect

How can I replace single cell references with ranges

I have 5 columns ((a)uptick, (b)downtick, (c)original, (d)current), and (e) Stored Value. All columns need to be a range of rows. When d2 changes I want to compare it to e2 and if d2>e2 then bump the counter in a2 by 1 (uptick), if d2<e2 then bump the counter in b2 (downtick). I have it working with many if and elseif statements but would rather use less code using variables for the range. To detect the changing cell I use "If Not Intersect (Target, Range("d2:d10")) Is Nothing Then...."
I cannot seem to figure out how to replace specific cell references with ranges. Any help would be most appreciated!
Sample Code below not using ranges yet.
Private Sub Worksheet_Change(ByVal Target As Range)
If Not Intersect(Target, Range("D2:D10")) Is Nothing Then
If Target.Value > Range("E2") Then
Range("A2") = Range("A2") + 1
Pause 2#
Range("E2") = Target.Value
ElseIf Target.Value < Range("E2").Value Then
Range("B2") = Range("B2") + 1
Pause 2#
Range("E2") = Target.Value
End If
End If
End Sub
I assume you want to change the cell value in the same row that the value was entered in column D, i.e. if D4 has been changed, then adjust A4 or B4. To do that, you need the row number of the changed cell. You can extract that with target.row. Throw that into a variable and use the variable instead of the row number in the Range() property.
Private Sub Worksheet_Change(ByVal Target As Range)
If Not Intersect(Target, Range("D2:D10")) Is Nothing Then
dim myRow as long
myRow = target.row
If Target.Value > Range("E" & myRow) Then
Range("A" & myRow) = Range("A" & myRow) + 1
Pause 2#
Range("E" & myRow) = Target.Value
ElseIf Target.Value < Range("E" & myRow).Value Then
Range("B" & myRow) = Range("B" & myRow) + 1
Pause 2#
Range("E" & myRow) = Target.Value
End If
End If
End Sub
You could use .Offset to get the same result. The following code assumes you're only interested in the range D2:D10 and aren't concerned if the value in column D equals the value in column E.
Private Sub Worksheet_Change(ByVal Target As Range)
If Not Intersect(Range("D2:D10"), Target) Is Nothing Then
If Target.Rows.Count > 1 Then Exit Sub
If Target > Target.Offset(, 1) Then
Target.Offset(, -3) = Target.Offset(, -3) + 1
Else
If Target < Target.Offset(, 1) Then
Target.Offset(, -2) = Target.Offset(, -2) + 1
End If
End If
End If
End Sub

How to match multiple criteria and get a message

In Excel VBA I would like to match 3 criteria out 3 columns and get a message if there is any match.
My code so far is:
Private Sub Worksheet_Change(ByVal Target As Range)
If Range("A1:A10").Value = "America" And Range("B1:B10").Value = "cloudy"
And Range("C1:C10").Value > 30 Then
MsgBox "This is the promised land!"
End If
End Sub
I get an error that there is a problem with different values.
A different approach but works similar.
Dim i As Integer
For i = 2 To 10 ' Put something more variable instead of 10
If Range("A" & i).Value = "Value4" And Range("B" & i).Value = "Value8" And Range("C" & i).Value > 30 Then
MsgBox "Test"
End If
Next i
Loop over each row:
Sub ceckit()
Dim cell As Range, A As Range
Set A = Range("A1:A10")
For Each cell In A
With cell
If .Value = "America" And .Offset(0, 1).Value = "cloudy" And .Offset(0, 2).Value > 30 Then
MsgBox "This is the promised land!"
End If
End With
Next cell
End Sub

Why IsDate doesn't work as expected ? and how do I get date value of the next cell in a column? [duplicate]

This question already has answers here:
IsDate function returns unexpected results
(2 answers)
Closed 3 years ago.
I am currently working on a sheet, specifically column that contains various data types; where I am interested in calculating difference between the first date occured in the column and the next one to it (because the main problem is that the data in the column is heterogeneous and I am interested just in succession ).
So for each cell in the range I have to check whether is a Date , and if so calculate difference between the actual date and the that of the next cell.
I have tried some code but all I can say it is not stable since the IsDate function is acting wierd and seems to change the outcome for different reasons but never the same.
Sub loopDate()
Dim rnge, cell As range
Set rnge = range("P1:P21")
Application.ScreenUpdating = True
For Each cell In rnge
cd = cell.Value2
If IsDate(cd) = True Then
If IsDate(ActiveCell.Offset(1, 0)) = True Then
n = DateDiff("d", cd, ActiveCell.Offset(1, 0))
If n < 0 Then
MsgBox "here is a difference " & n
Else
MsgBox "normal pos diff " & n
End If
Else
MsgBox "contenent of the this cell isnt date intIF "
End If
Else
MsgBox "contenent of the this cell isnt date outIF "
End If
Next
End Sub
I am expecting either a negative or positive number that will refer to difference between two dates and tell weather we still gave time or we already got the deadline passed.
thanks for any help or suggestions about the code above.
try this:
Sub loopDate()
Dim rnge, cell As Range
Set rnge = Range("P1:P21")
For Each cell In rnge
If IsDate(cell) = True Then
If IsDate(cell.Offset(1, 0)) = True Then
n = DateDiff("d", cell, cell.Offset(1, 0))
If n < 0 Then
MsgBox "here is a difference " & n
Else
MsgBox "normal pos diff " & n
End If
Else
MsgBox "contenent of the this cell isnt date intIF "
End If
Else
MsgBox "contenent of the this cell isnt date outIF "
End If
Next
End Sub
If I understand you correctly, this is what you're trying to achieve; I have cleaned up some of the unnecessary bits and now you just have to edit DateCol and FindLastRow as is necessary.
Sub loopDate()
'Dim rnge As Range, cell As Range
Dim DateCol As Integer, FindLastRow As Single Dim i As Single
'Set rnge = Range("P1:P21")
'Application.ScreenUpdating = True
' For Each cell In rnge
DateCol = 16
FindLastRow = 21
For i = 1 To FindLastRow
' cd = cell.Value2
If IsDate(Cells(i, DateCol)) Then
If IsDate(Cells(i, DateCol + 1)) Then
n = DateDiff("d", Cells(i, DateCol).Value, Cells(i, DateCol + 1).Value)
If n < 0 Then
MsgBox "here is a difference " & n
Else
MsgBox "normal pos diff " & n
End If
Else
MsgBox "contenent of the this cell isnt date intIF "
End If
Else
MsgBox "contenent of the this cell isnt date outIF "
End If
' Next
Next i
End Sub

Excel Time Format

Having trouble with time formatting.
I have set the cell to custom format 00:00.
Currently in column A a date is inputted, this can be as 0300 which converts to 03:00 which is perfect or you can just enter 03:00.
I now have a problem if a user enters 03;00 as i need this to display 03:00
how can i ensure that all times are in the hh:mm format and not in hh;mm etc.
This needs to auto change on input for anything in column A, except what is the header (A1:A5) although this should not be affected.
Thanks
On your sheets change event you would place the following code:
Private Sub Worksheet_Change(ByVal Target As Range)
If Target.CountLarge = 1 And Target.Column = 1 And Target.Row > 5 Then
Target.Value2 = Replace(Target.Value2, ";", ":")
End If
End Sub
Explaining the code... it first checks to make sure that the change isn't on multiple cells (ie paste) and that the change is on column A below Row 5. If it does pass the conditional it simply replaces ; for :.
This does what i require.
Private Sub Worksheet_Change(ByVal Target As Excel.Range)
Dim xStr As String
Dim xVal As String
Set rng1 = Range("A:A")
Set rng2 = Range("C:C")
Set rng3 = Range("I:I")
On Error GoTo EndMacro
If Application.Intersect(Target, Union(rng1, rng2, rng3)) Is Nothing Then Exit Sub
If Target.Count > 1 Then Exit Sub
If Target.Value = "" Then Exit Sub
If Target.Row < 5 Then Exit Sub
Application.EnableEvents = False
With Target
If Not .HasFormula Then
Target.Value = Replace(Target.Value, ";", ":")
Target.Value = Left(Target.Value, 5)
xVal = .Value
Select Case Len(xVal)
Case 1 ' e.g., 1 = 00:01 AM
xStr = "00:0" & xVal
Case 2 ' e.g., 12 = 00:12 AM
xStr = "00:" & xVal
Case 3 ' e.g., 735 = 07:35 AM
xStr = "0" & Left(xVal, 1) & ":" & Right(xVal, 2)
Case 4 ' e.g., 1234 = 12:34
xStr = Left(xVal, 2) & ":" & Right(xVal, 2)
Case 5 ' e.g., 12:45 = 12:45
xStr = Left(xVal, 2) & Mid(xVal, 2, 1) & Right(xVal, 2)
Case Else
Err.Raise 0
End Select
.Value = Format(TimeValue(xStr), "hh:mm")
End If
End With
Application.EnableEvents = True
Exit Sub
EndMacro:
Application.EnableEvents = True
End Sub
Thanks

Resources