MS Access 2013 - Getting unfounded Division by zero error - sql

I have a routine that writes totals to textboxes to prevent expensive 'Dlookup' processing time.
Some of the totals produce a percentage rate so depend on a denominator.
The error seems to be due to lag of some sort because the denominators are never blank or zero. For example, as long as there are values in this database - which there are always an abundance of, these denominators will never be zero.
At any rate, here is the line that gets the error ( I get an error 11)
Dim db As DAO.Database
Dim rs As DAO.Recordset
Dim rsSP As DAO.Recordset
Set db = CurrentDb
--->Set rs = db.OpenRecordset("TOTALS_FINAL", dbOpenSnapshot)
What can I do to trap this error? It only happens occasionally and when I tell the use to restart the database (which frees up some resources) it usually corrects the problem.
Here is the SQL for TOTALS final
SELECT
"Total Program" AS BL
,TOTALS_COB_ALL_TOTALS.AFP_ AS AFP
,TOTALS_COB_ALL_TOTALS.ALLT_ AS ALLT
,TOTALS_COB_ALL_TOTALS.SP_C_ AS SP_C
,TOTALS_COB_ALL_TOTALS.SP_O_ AS SP_O
,TOTALS_COB_ALL_TOTALS.COMMITS_ AS COMMITS
,TOTALS_COB_ALL_TOTALS.OBS_ AS OBS
,TOTALS_COB_ALL_TOTALS.RA_ AS RA
,IIF([SP_C_] = 0, 0, [COMMITS_] / [SP_C_]) AS COM_SP_RATE
,IIF([SP_O_] = 0, 0, [OBS_] / [SP_O_]) AS OBS_SP_RATE
,IIF(Nz([AFP_], 0) = 0, 0, Nz([OBS_], 0) / [AFP_]) AS OB_AFP_RATE
,TOTALS_COB_ALL_TOTALS.UNC_ AS UNC
,TOTALS_COB_ALL_TOTALS.AVL_ AS AVL
,TOTALS_COB_ALL_TOTALS.ACW_ AS ACW
,7999 AS SO
FROM
TOTALS_COB_ALL_TOTALS;
The query right before it just collects totals that are used to produce the final percentages

The reason is, that IIf always evaluates both expressions even though only one is used.
So use a "double-iif" that divides by one and not zero:
,IIF([SP_C_] = 0, 0, [COMMITS_] / IIf([SP_C_] = 0, 1, [SP_C_])) AS COM_SP_RATE
,IIF([SP_O_] = 0, 0, [OBS_] / IIf([SP_O_] = 0, 1, [SP_O_])) AS OBS_SP_RATE
,IIF(Nz([AFP_], 0) = 0, 0, [OBS_] / IIf(Nz([AFP_], 0) = 0, 1, [AFP_]) AS OB_AFP_RATE

Related

How to get duration between two times in vb .NET

I have two times that I want to get the duration between them.
For example, 00:00:05,967 --> 00:00:08,285 that duration becomes 2.318
Thank you all for helping me.
Use TimeSpan
Dim t1 As New TimeSpan(0, 0, 0, 5, 967)
Dim t2 As New TimeSpan(0, 0, 0, 8, 285)
Console.WriteLine(t2 - t1)

Select a DataRow based on two column conditions

I have a datatable that I know to be empty at the beginning, but as I populate it, I am unable to get the datarow back out of it based on two column conditions, so it is doubling (or more) the number of rows.
I may be going about this wrong, but my aim is to check if the row exists in the datatable if the 2 conditions are met and then get the row if it does exist and modify it.
Dim qryB = From drw As DataRow In oDT_Signals.Rows
Where drw("SG").Equals(sgrp) AndAlso drw("EP").Equals(srchPt)
Select drw
Dim rslt = qryB.SingleOrDefault
If IsNothing(rslt) Then
ed.WriteMessage("Row does not exist")
oDT_Signals.Rows.Add(0, 0, sgrp, rw.sPt, PtList.IndexOf(rw.sPt), rw.ePt, PtList.IndexOf(rw.ePt), "NIL", rw.Len, 0, rw.Phases, rw.Size, rw.Core, rw.Ins, rw.Temp, rw.Table, "NIL",
"NA", "NA", rw.mVAm, ldVal, 0, 0, rw.Zs, 0, 0, rw.ePt.X, rw.ePt.Y, rw.mVtest, 0, 0, rw.Ztest, 0, 0)
Else
ed.WriteMessage("Row does exist")
Dim dr As DataRow = qryB.First
dr("LOAD") = Math.Round(ldVal + dr("LOAD"), 2, MidpointRounding.AwayFromZero)
End If
The issue is rslt is always nothing, when I know it is not the case. Is anyone able to help me determine what I am doing wrong that is is always adding the row? The console just keeps saying "Row does not Exist".
I haven't tested to be sure but I'm fairly certain that the issue is your use of the Object.Equals method, which will test for reference equality. If value equality is what you're interested in, test for that. Change this:
Where drw("SG").Equals(sgrp) AndAlso drw("EP").Equals(srchPt)
to something like this:
Where drw.Field(Of String)("SG") = sgrp AndAlso drw.Field(Of String)("EP") = srchPt
If the columns don't contain Strings, change the generic type of the Field calls.

Does DateTime include second leap function?

In this article: Are .Net's DateTime methods capable of recognising a Leap Second?, the writer gets the answer "It (DateTime) does not include the number of ticks that are attributable to leap seconds."
However, the following code shows that .Net DateTime supports leap seconds. Could any expert explain why?
Dim GPS_Time_Base_Point As DateTime = New DateTime(1980, 1, 6, 0, 0, 0, DateTimeKind.Unspecified)
Dim A_test_time As DateTime = New DateTime(2019, 4, 16, 18, 29, 0, DateTimeKind.Unspecified)
Dim TimeSpan As TimeSpan = A_test_time - GPS_Time_Base_Point
Dim GPS_Time_At_LIGO_for_2019_4_16_18_29_0 As UInt64 = 1239474558 'https://www.andrews.edu/~tzs/timeconv/timeconvert.php
Dim DifSeconds As Integer = TimeSpan.TotalSeconds - 1239474558
Debug.Print(" Second dif:" + CDbl(DifSeconds).ToString)
The output is "Second dif:-18", which is just equal to the leap second dif for gpstime - UTC time.

How to use a variable in a Virtual-Key statement in VB.Net

I'm trying to use a variable in a Virtual-Key statement in VB.Net, but I keep getting errors. What is the correct syntax? Without the variable, the code looks like this:
<DllImport("user32.dll")> _
Public Shared Sub keybd_event(bVk As Byte, bScan As Byte, dwFlags As UInteger, dwExtraInfo As UInteger)
End Sub
Const VK_1 As Integer = &H31
keybd_event(VK_1, 0, 0, 0)
keybd_event(VK_1, 0, KEYEVENTF_KEYUP, 0)
I'm trying to do:
keybd_event(digit, 0, 0, 0)
keybd_event(digit, 0, KEYEVENTF_KEYUP, 0)
where "digit" is the variable. I've tried:
Dim digit as Byte = "VK_" & 1
Dim digit as Integer = "VK_" & 1
Dim digit as String = "VK_" & 1
But I get the error: "Conversion from string "VK_1" to type 'Byte' is not valid." and "Conversion from string "VK_1" to type 'Integer' is not valid."
I've tried:
keybd_event(VK_digit, 0, 0, 0)
But got the error "VK_digit is not declared. It may be inaccessible due to its protection level."
I also tried converting the sting to bytes and using Integer.Parse on the string but that caused errors too.
Variable names cannot be concatenated. What you're currently trying to do with the digit variable is impossible, I'm afraid. You get the errors because in your attempts you are just taking a normal string and trying to convert that into a number (which doesn't work, since for example "VK_1" contains letters and other non-numeric characters).
However if you want to dynamically specify a number key, there are a few ways.
For starters: All the VK_ key codes can be found in the System.Windows.Forms.Keys enumeration, so you don't have to lookup every key you want to use.
Secondly: The numbers' key codes follows each other. Number 0 has the key code 48, 1 has the key code 49, 2 has 50, and so on...
Thanks to the second thing I mentioned we can make it easy for ourselves by just taking the key code for 0, and to that add the number that we want.
The simple solution:
Dim digit As Integer = 3 'Cannot go below 0 nor above 9.
keybd_event(Keys.D0 + digit, 0, 0, 0)
keybd_event(Keys.D0 + digit, 0, KEYEVENTF_KEYUP, 0)
The second, more complicated, solution is to parse a string into an enum value:
Dim digit As Integer = 3
Dim Key As Keys = [Enum].Parse(GetType(Keys), "D" & digit, True)
keybd_event(Key, 0, 0, 0)
keybd_event(Key, 0, KEYEVENTF_KEYUP, 0)
The good thing with the second solution is that it works for more than just numbers:
Dim Letter As String = "F"
Dim Key As Keys = [Enum].Parse(GetType(Keys), Letter, True)
keybd_event(Key, 0, 0, 0) 'Presses "F".
keybd_event(Key, 0, KEYEVENTF_KEYUP, 0)

finding a time range using case statement

good evening everyone...
could anyone help me on this?
With a "time value", eg. 08:00:00...
i want to find the range that this value falls in using case statement...
i am not good in using the time format...
anyone can help?
This is just an example: (the code is not working...is just an example)
datime = Now().ToString("hh:mm:ss")
Select Case datime
Case "08:00:00" To "09:00:00"
lblRange.Text = i.ToString()
Case "09:00:01" To "09:14:59"
lblRange.Text = (i - 0.25).ToString()
Case "09:15:00" To "09:29:59"
lblRange.Text = (i - 0.5).ToString()
If you don't follow Tim's advice you can use this
Dim timeToCheck As DateTime = #7:10:00 PM#
Select Case timeToCheck.TimeOfDay
Case New TimeSpan(8, 0, 0) To New TimeSpan(9, 0, 0)
Stop
Case New TimeSpan(9, 0, 1) To New TimeSpan(9, 14, 59)
Stop
Case New TimeSpan(9, 15, 0) To New TimeSpan(9, 29, 59)
Stop
Case New TimeSpan(19, 0, 0) To New TimeSpan(19, 14, 59)
Stop
Case Else
Stop
End Select
You do NOT want to use strings.
In this case i wouldn't use the Select...Case statement, it should be used with simple conditions only. You can use an If-Else instead.
But since you're actually checking if a given time is between a range you could also use following code which uses LINQ.
First you need to define a collection which holds all ranges. You can use a List(Of YourClass) or even an array of an anoymous type:
Dim ranges = {
New With {.Start = TimeSpan.FromHours(8), .End = TimeSpan.FromHours(9)},
New With {.Start = New TimeSpan(9, 0, 1), .End = New TimeSpan(9, 14, 59)},
New With {.Start = New TimeSpan(9, 15, 0), .End = New TimeSpan(9, 29, 59)}
}
You want to compare TimeSpans, you get the current time by Date.Now.TimeOfDay.
Dim now As TimeSpan = Date.Now.TimeOfDay
Dim matchingRange = ranges.
FirstOrDefault(Function(r) now >= r.Start AndAlso now <= r.End)
Enumerable.FirstOrDefault returns the first where the time is in range or Nothing otherwise.
If matchingRange IsNot Nothing Then
lblRange.Text = String.Format("Between {0} and {1}",
matchingRange.Start,
matchingRange.End)
End If