find max value in multiple split loops - vbscript

I try to isolate the one maximum value from 4 split loops and have so far not unraveled the mystery.
The recordset XlsRecWeeks comes from an excel worksheet field [Scheduled Weeks] containing weeknumbers as values like
6,
7,
6-22,
9-12;14-24
and so on, representing either one week, a period between two weeks or even several periods of multiple weeks in each field.
I managed to split the fields into an array of single weeks, and i need to determine the single highest weeknumber of all the values in the resulting array.
May i ask for an advice?
Here's the code so far
do while not XlsRecWeeks.EOF
If not isnull(XlsRecWeeks("scheduled weeks")) Then
weekgroups=Split(XlsRecWeeks("scheduled weeks"), ";")
if ubound(weekgroups) > 0 then
for each weekintervals in weekgroups
weekinterval=Split(weekintervals, "-")
if ubound(weekinterval)> 0 then
for weeknrs = weekinterval(0) to weekinterval(1)
Response.Write weeknrs & "<br />"
next
else
Response.Write weeknrs & "<br />"
end if
next
else
weekinterval=Split(XlsRecWeeks("scheduled weeks"), "-")
if ubound(weekinterval)> 0 then
for weeknrs = weekinterval(0) to weekinterval(1)
Response.Write weeknrs & "<br />"
next
else
Response.Write XlsRecWeeks("scheduled weeks") & "<br />"
end if
end if
else
end if
XlsRecWeeks.movenext
loop

You need to use a variable (maxWeek) to contain the max week number, initially set low, and a function to compare whatever week numbers you get from the data to this value (checkMax). All you do is call the function any time you get a new week number and at the end of the process the value of the maxWeek variable is the highest week number in the data set. You could get funky by putting the week numbers into an array and sorting it but that would be overkill for what you are doing.
Couple of notes of caution: 1) the code is not tested but its not hard to understand and you seem competent; 2) note that you need the cInt() or cLng() function to force the comparison of the week number to be numeric - if you neglect this you will get odd results. 2) I reformated / indented the code but the logic is as your original - you will find that your code is easier to read and pass on if you format and space it for readability and comment it for explanation - worth considering as otherwise you'll never get promoted as all the know-how will rest with you [Assuming you are new to coding - sorry if preaching]
Edit: Error in first edit - I used the return which is an invalid verb in VBS. As everyone knows, to return a value from a function you have to set the function name as if it were a variable. CheckMax() function altered.
Edit: Corrected use of val() to cInt() function. The val() function is a VB6 function that did not get ported to VBS.
dim maxWeek
maxWeek = -1
do while not XlsRecWeeks.EOF
If not isnull(XlsRecWeeks("scheduled weeks")) Then
weekgroups=Split(XlsRecWeeks("scheduled weeks"), ";")
if ubound(weekgroups) > 0 then
for each weekintervals in weekgroups
weekinterval=Split(weekintervals, "-")
if ubound(weekinterval)> 0 then
for weeknrs = weekinterval(0) to weekinterval(1)
Response.Write weeknrs & "<br />"
maxWeek = checkMax(Cint(weeknrs)), maxWeek)
next
else
weeknrs = weekinterval(0)
Response.Write weeknrs & "<br />"
maxWeek = checkMax(Cint(weeknrs)), maxWeek)
end if
next
else
weekinterval=Split(XlsRecWeeks("scheduled weeks"), "-")
if ubound(weekinterval)> 0 then
for weeknrs = weekinterval(0) to weekinterval(1)
Response.Write weeknrs & "<br />"
maxWeek = checkMax(Cint(weeknrs)), maxWeek)
next
else
Response.Write XlsRecWeeks("scheduled weeks") & "<br />"
weeknrs = XlsRecWeeks("scheduled weeks")
maxWeek = checkMax(Cint(weeknrs)), maxWeek)
end if
end if
end if
XlsRecWeeks.movenext
loop
' maxWeek now holds max week value.
response.write(maxWeek)
function checkMax(theVal, currentMax)
checkMax = currentMax
if theVal > checkMax then
checkMax = theVal
end if
end function

Related

How to read dt_DBTIME2 with VBScript

I'm trying to read a recordset from SQL database were some field are of type time(n).
When I read a row (recordset.Fields(n)), VBScript stops at this field with a 'multiple step error'.
I tried to set a variable with the recordset, so:
Dim a
Set a = recordset.Fields(specific time column)
I tried to cast the field.
I tried to find any information about this specific type, but I can't find any information about this time structure, besides it contains hour, minute, second and fractional parts.
ReDim iArr(iColumnCount)
While Not objRecordset.EOF
For iColumnIndex = 0 To (iColumnCount-1)
'SQL_FIELDTYPE_TIME is a constant at top of page with value 145
If objRecordset.Fields(iColumnIndex).Type = SQL_FIELDTYPE_TIME Then
'Tried so much over here...
Dim Tme, Str
Set Tme = objRecordset.Fields.Item(iColumnIndex)
iArr(iColumnIndex) = CStr(clDBTime(Tme).Hour)
Set Tme = Nothing
Else
iArr(iColumnIndex) = objRecordset.Fields.Item(iColumnIndex)
End If
If Err.Number <> 0 Then
fLogData("Ophalen data (" + oDB.strDatabaseNaam + ") rij " + _
CStr(objRecordset.AbsolutePosition) + " kolom " + _
CStr(iColumnIndex) + " mislukt: " + Err.Description)
Err.Clear
End If
Next
List.Add i, iArr
i = i + 1
objRecordset.MoveNext 'Next row
Wend
Errors I'm getting:
Object doesn't support this property
Multiple step error
Type mismatch
etc. etc.
Anyone who can help me out how to read the time value from SQL in VBScript?
EDIT: solved! Cost almost 4h trial-error but there's a solution:)
Changed the SQL select statement to:
SELECT COL, COL,... (this are the 'usual' columns),CAST(TIMECOL -this is the time(n) column- as varchar),CAST(TIMECOL2 -this is the time(n) column- as varchar) FROM tabel
And within code: TimeValue(read value - from recordset.fields...) (this is to change varchar back to time)
And .. it just works great!
Edit2: recordset code:
if iResCount > 0 and iColumnCount > 0 then
redim iArr(iColumnCount)
while not objRecordset.EOF
for iColumnIndex = 0 to (iColumnCount-1)
iArr(iColumnIndex) = objRecordset.Fields.Item(iColumnIndex)
if Err.Number <> 0 then
fLogData("Ophalen data ("+oDB.strDatabaseNaam+") rij "+cstr(objRecordset.AbsolutePosition)+ " kolom "+cstr(iColumnIndex)+" mislukt: "+Err.Description)
Err.Clear
end if
next
List.Add i, iArr
i = i + 1
objRecordset.MoveNext 'Next row
wend
set oResult = List'CreateObject("Scripting.Dictionary")
end if
And an example of a function call:
'fGetRecord(DB, Table, Columns, Condition, Field to sort on, Type of sort)
fGetRecord(oHoofdDB,CONST_HDB_STR_TBL_KALENDER,CONST_HDB_STR_KAL_ID+","+CONST_HDB_STR_KAL_NAAM+",CAST("+CONST_HDB_STR_KAL_STARTIJD+" as varchar),CAST("+CONST_HDB_STR_KAL_STOPTIJD+" as varchar)",CONST_HDB_STR_KAL_NAAM+"='"+Naam+"'", "", SORTEER_OPLOPEND)
John

Microsoft VBScript runtime error '800a000d' Type mismatch: 'LastID'

I do a function to assign an ID. But when I click button, this error comes out.
Microsoft VBScript runtime error '800a000d' Type mismatch: 'LastID'
Public function AssignSanctionID(DeptID,SectID,SanctionType)
REM obtain Transaction ID
dim CmdX
dim SQLX
dim RsX
dim Prefix
dim LastID
dim CurrID
dim NewCurrID
'- Set Connection
HariNi=now()
Tahun=year(HariNi)
Bulan=month(HariNi)
if len(bulan)=1 then
Bulan= "0" & Bulan
end if
If Cint(Tahun) < 2016 then
Pref1= DeptID & "/" & SectID & "/"
Prefix=DeptID & "/" & SectID & "/" & Tahun & "/" & Bulan & "/"
else
Pref1= DeptID & "/%/" & SectID
Prefix=DeptID & "/" & Tahun & "/" & Bulan & "/"
end if
set CmdX = server.CreateObject("ADODB.Command")
Set RSX = Server.CreateObject("ADODB.Recordset")
SQLX = " SELECT * FROM Sanction " _
& " WHERE SanctionID like '%" & Pref1 & "%' " _
& " ORDER BY ID DESC"
CmdX.ActiveConnection = objconn
CmdX.CommandText = SQLX
RsX.Open CmdX,,0,1
if not(RsX.BOF and RsX.EOF) then
If Cint(Tahun) < 2016 then
LastID = right(RsX("ID"),4)
else
LastID = mid(RsX("ID"),13,4)
end if
else
if Bulan="04" then
LastID=0
end if
end if
RsX.Close
set RsX = nothing
'Set ID
If LastID<>"" then
'CurrID = left(4)
CurrID=int(LastID)+1
end if
if len(currid)>0 then
select case len(currid)
case 1
newcurrid = "000" & currid
case 2
newcurrid = "00" & currid
case 3
newcurrid = "0" & currid
case 4
newcurrid = currid
end select
else
NewCurrID="0001"
end if
If Cint(Tahun) < 2016 then
NewCurrID=Prefix & NewCurrID
else
NewCurrID=Prefix & NewCurrID & "/" & SectID
end if
AssignSanctionID = NewCurrID
end function
Hard to help if I don't see the data.
From quick view of the code the issue is here:
CurrID=int(LastID)+1
You are trying to cast LastID but are you sure that it is convertible? Could list all possible values?
Short answer: CInt only works with Numerical values. If you have letters in your value, then Cint wont work.
Bit longer answer:
Having read the Blog that we should be more welcoming (https://stackoverflow.blog/2018/04/26/stack-overflow-isnt-very-welcoming-its-time-for-that-to-change/?cb=1), here is a very general answer, but that might lead you on the correct way to fix it yourself.
Type Mismatch is an error you can get when using a variable the wrong way. For example if you try to do numerical functions with Strings (which means the variable contains letters a-z etc) you will get "Type Mismatch" as you cant add or subtract text in a mathematical way... On the other hand you cant add Integer variables (the variable only contains a number AND isnt contained within "quote marks").
So below is a few ways to assigna a variable and what type it becomes:
LastID=1 'This makes LastID an INT (number)
LastID="1" 'This makes LastID a String but a CInt(LastID) can turn it into an INT because it ONLY contains numbers.
LastID="IT" 'This makes LastID a String that CANT in any way be cast to INT as it contains letters.
LastID=IT 'This row will either create an error except if you already have a variable called IT, then LastID will get the same value as the IT variable...
This should hopefully get you on your way to fix this issue...

Round function not working properly

I tried to round off value using VBscript
here is my code
sql = "select lastcode from " & session("gasbook") & ".acccode where account='" _
& Trim(rsgrn.fields("stockcode")) & "'"
response.write sql
rs.Open sql, cn
if err.number<>0 then
cn.rollbacktrans
call HandleError(err.number,err.description,err.source)
Response.End
else
if (rs.EOF and rs.BOF) then
cn.RollbackTrans
Response.Write "GAS Code doesn't exist in " & session("gasbook")
Response.End
else
If clng(rs.Fields("lastcode")) <> 0 Then
cn.RollbackTrans
Response.Write "Stock Account must be control account in " _
& session ("gasbook")
Response.End
End If
end if
end if
dim tmp
tmp = rsgrn.Fields("amount")
response.write tmp
response.write round(tmp)
tmp has value 2984.5, but when I apply round on tmp it convert into 2984 instead of 2984.5.
The number is rounded to 2948 because the .Net framework follows the Bankers Rounding algorithm off of the IEEE 754 standard. It is not a question of if the number was rounded, it is rounded to the nearest even number due to standards.
Evidence: Here. and Here.
So, the round function is working perfectly to the IEEE Standards.
When in doubt, read the documentation. Without the optional second parameter numdecimalplaces, the Round function returns an integer:
numdecimalplaces
Optional. Number indicating how many places to the right of the decimal are included in the rounding. If omitted, integers are returned by the Round function.
Change the line
response.write round(tmp)
to
response.write round(tmp, 1)
if you want the value rounded to one decimal.

What is wrong with VB str() function?

The abnormal behaviuor of the str() or val() functions made my days horrible, the following bug get me 2 days to find it.
temp = Val(currentYear)
temp = temp + 1
nextYear = Str(temp)
MsgBox "YY" & currentYear & "YY"
MsgBox "YY" & nextYear & "YY"
The initial value of currentYear is "2010"
The result should be:
YY2010YY
YY2011YY
however, the result is:
YY2010YY
YY 2011YY
This bug is gross.After that, I add a line next to my code:
temp = Val(currentYear)
temp = temp + 1
nextYear = Str(temp)
nextYear = LTrim(nextYear)
MsgBox "YY" & currentYear & "YY"
MsgBox "YY" & nextYear & "YY"
Then the result come as expected. Can anyone explain this? Thanks.
You should use CStr instead.
Str uses a space to indicate it is positive, while CStr does not.

VBScript Data Validation - Numeric 1 Results in Infinite Loop

DISCLAIMER: I'm still an uber-n00b with programming concepts and know just enough VBS to hurt myself, so I'm likely to slur/slaughter some of the terms/concepts/ideas that are entailed with this program I'm trying to write. You, the vastly superior programmer who has every right to flame me, have been warned.
I've been trying to write a VBScript to validate data, specifically Dates. Since my users are kind of poor with keyboards, I figured I'd make it easy by separating the entry of each part of the date (Month & Day only, I've got the Year set statically).
Previously, I was having problems with validating the numbers with only 1 "Do...Loop", as I was trying to verify if it was Numeric Input and checking at the same time if it was within the specified range (1 - 12, for the 12 months of the year).
This is what the previous code roughly looked like:
Do
' If...Then Statements Here
Loop Until (dtFirstMonth > 0) _
And (dtFirstMonth < 13) _
And IsNumeric(dtFirstMonth) _
And (dtFirstMonth <> "") _
And (dtFirstMonth <> vbNull)
This often resulted in "Data Type Mismatch" errors, so I had to split the Validation Critera to two separate "Do...Loop" statements, as you can see in the current code I have below:
Sub srTest()
Do
dtFirstMonth = InputBox("Please Enter a Numeric Month for the Starting Range", _
"Starting Range Month")
If (dtFirstMonth = vbNull) _
Or (dtFirstMonth = "") _
Or Not IsNumeric(dtFirstMonth) Then
MsgBox "Please Enter a Valid Numeric Month",, "Enter Month Number"
ElseIf (dtFirstMonth <> vbNull) _
And (dtFirstMonth <> "") _
And IsNumeric(dtFirstMonth) Then
Do
dtFirstMonth = Round(dtFirstMonth)
Wscript.Echo dtFirstMonth ' Infinite Loop Here (Basically, As Soon As We Get Into Loop with a Value of 1, We're Stuck)
dtFirstMonth = CInt(dtFirstMonth)
' Must Convert User Input to Integer to
' Prevent Data Mismatch Errors In
' Following "If" Statement; Besides,
' It Passed the First Test to be a
' Numeric Value in the First Place
If (dtFirstMonth < 1) Or (dtFirstMonth > 12) Then
MsgBox "Please Enter a Valid Numeric Month",, "Enter Month Number"
Exit Do
' Drop Out of 2nd Level Loop to
' Enter Into 1st Level Loop
End If
Loop Until (dtFirstMonth > 0) _
And (dtFirstMonth < 13) _
And IsNumeric(dtFirstMonth) _
And (dtFirstMonth <> "") _
And (dtFirstMonth <> vbNull)
If (dtFirstMonth < 1) Or (dtFirstMonth > 12) Then
dtFirstMonth = ""
End If
' dtFirstMonth Was Converted to Integer Earlier
' This is to Meet the Value that Didn't Pass
' the Nested Do & If Statement (Level 2 Do Loop)
' Sets dtFirstMonth to "Empty String" to Continue
' Looping in the Level 1 "Do...Loop" Statement;
' If Omitted, Level 1 "Do...Loop" is Satisfied,
' Thus Ending the Subroutine (Since the Value
' of dtFirstMonth is Still a Numeric Value)
End If
Loop Until IsNumeric(dtFirstMonth) _
And (dtFirstMonth <> "") _
And (dtFirstMonth <> vbNull)
Wscript.Echo dtFirstMonth
End Sub
srTest
I had to set up the 1st "Do...Loop" to check that the User Input (dtFirstMonth) was a indeed a Numeric Value and not a Null Value nor an Empty String. The Nested "Do...Loop", or 2nd "Do...Loop", statement is where I have the same Criteria plus the extra Criteria defining the desired ranges (any number between 1 and 12).
This is working perfectly for number 2-12, but when the script parses the number 1, I enter into an Infinite Loop.
I've checked to make sure that the Infinite Loop is occurring in the 2nd "Do...Loop" by replacing the entire 2nd "Do...Loop" section with "Wscript.Echo dtFirstMonth". By doing this, I get the expected results: a single Echo, not an infinite number of them (technically, I get 2, as I do have another "Wscript.Echo dtFirstMonth" string at the bottom of the Subroutine for the purpose of debugging, but either way, it's not an Infinite Loop).
I've also changed the criterion for the lower range to be like this, yet this doesn't remediate the error:
Do
' If...Then Statements Here
Loop Until (dtFirstMonth >= 1)
I've also tried this, with no resulting success:
Do
' If...Then Statements Here
Loop Until (dtFirstMonth >= CInt(1))
In all reality, there really is no need for this segment, since I converted the User's Input to an integer anyway.
Since this was starting to get confusing, I decided to add the "Round" statement before the script passed the User's Input to the "CInt" function, hoping that it would make sure that it wasn't getting caught as a 0 value or decimal value somehow; yes, this is irrational thought on my part, but I still wanted to explore all avenues (there's also the fact that I have some users with "Fat Finger Syndrome" and some others with "Abuse The Program" mentality, so I figured I'd make sure the script accounted for decimal entries). I added the "Round" string before and after the nested "Do...Loop" and I still had the Infinite Loop issue.
This is as far as I've been able to get on this and now I'm stuck.
I realize that there are likely better ways to do Date/Time Validation in VBScript, and I'm certainly open to any new suggestions, but I'd love to solve this for the pure sake of edification.
Way too much code for a simple input of a number. Just try to keep it short and simple. Example:
Do
dtm = InputBox("Please Enter a Numeric Month for the Starting Range", _
"Starting Range Month")
Select Case True
Case isNull(dtm), (not isNumeric(dtm)), dtm = "", dtm = empty, (dtm < 1 OR dtm > 12)
' too exhaustive, but just for the sake of the example.
MsgBox "Please enter an amount between 1 and 12"
Case else
' Hey, this seems to be a valid amount!
Exit do
End Select
Loop While True
' Do something with dtm
Just showed you some creative Select Casing, this supports lazy exit, so if a value is Null, it escapes before getting evaluated where evaluating could throw an error.
The problem is with your attempt to check for null values:
(dtFirstMonth = vbNull)
The proper way to check for nulls, as demonstrated in AutomatedChaos' answer, is with the IsNull function. vbNull is actually a constant that's used with the VarType function. The value of vbNull is 1, which is why that particular value behaved differently from other entries. That's the fundamental problem, and if you replace every dtFirstMonth = vbNull with IsNull(dtFirstMonth), you won't get an infinite loop when entering 1.
Now, the actual place where your code infinitely loops is interesting. I would expect the first conditional If (dtFirstMonth = vbNull) to evalute true for an entry of "1", and you would get the message box "Please enter a valid numeric month". However, the Else condition is triggered. This is weird because normally, when you compare a string to a number, VBScript will attempt to convert the number to a string or vice versa, so if dtFirstMonth is "1", it should be equal to vbNull (which is 1). However, there appears to be a special case when you compare a string variable to an integer variable. See this example:
' vbNull = 1, built-in constant
dtFirstMonth = "1"
MsgBox (dtFirstMonth = vbNull) ' False
MsgBox ("1" = vbNull) ' True
MsgBox (dtFirstMonth = 1) ' True
MsgBox (CInt(dtFirstMonth) = vbNull) ' True
I don't know if this is a bug or just an obscure detail about VBScript's implicit conversion, but it does illustrate that implicit conversion can be unpredictable in VBScript.
As far as alternative methods go, you may be interested in the IsDate function, which returns True if the given expression can be converted into a date. It may not be ideal for your users and their keyboard skills, but it would reduce your code to:
Do
str = InputBox("Enter a date (MM/DD)")
If IsDate(str) Then
Exit Do
Else
WScript.Echo "Please enter a valid date"
End If
Loop
dt = CDate(str)
' Put your static year here; CDate will default to the current year
dtActual = DateSerial(2007, Month(dt), Day(dt))
WScript.Echo (dtActual) & " - Thanks!"
Note that IsDate should return False for the typical edge cases ("", Null, Empty, etc.), so there's no need for a separate check.
I found a simple program to generate Date and time from http://rindovincent.blogspot.com/p/vbscript-programs.html. I am pasting the same program with permission.
<html>
<body>
<center>
<script type="text/vbscript">
d=CDate("October 22, 2010")
document.write(d&"<br/>")
document.write("Current system date is:"&date&"<br/>")
document.write("Current system time is:"&time&"<br/>")
document.write(DatePart("m",Now())&"<br/>")
document.write(DateAdd("yyyy",1,"31-Jan-10") & "<br />")
document.write(MonthName(10,true)& "<br />")
fromDate="22-sep-10 00:00:00"
toDate="21-oct-10 23:59:00"
document.write(DateDiff("m",fromDate,toDate)&"<br />")
document.write(DateDiff("y",fromDate,toDate) & "<br />")
document.write(DateDiff("w",fromDate,toDate) & "<br />")
document.write(DateDiff("h",fromDate,toDate) & "<br />")
</script>
</center>
</body>
</html>

Resources