I am using VB.NET and Linq; I have two separate conditions that have to be satisfied. When I run them individually they work fine however when I combine them into a single statement with multiple where statements then I get 0 records returned.
If I run the first where clause without the 2nd I get 70 records
If I run the 2nd where clause without the first i get 5 records
When I run with both where clauses I get 0 records returned
Here is the code.
submissionDetails = (From r In model.NIBRS_ReportStatusByORI
Where (sCritera.ORI.Contains(r.OriginatingORI) _
And Not r.ReportType = "ZERO REPORT" _
And r.OccurrenceDate >= sCritera.BeginDate _
And r.OccurrenceDate <= sCritera.EndDate _
And (r.ActionCode <> "D"))
Where (sCritera.ORI.Contains(r.OriginatingORI) _
And r.ReportType.Equals("ZERO REPORT") _
And r.YearMonthDate >= sCritera.BeginDate _
And r.YearMonthDate <= sCritera.EndDate _
And (r.ActionCode <> "D"))
Select New ReportStatusDetails() With {
.ChangeDate = r.Insertdate,
.IncidentId = r.IncidentID,
.IncidentIdentifier = r.IncidentIdentifier,
.OriginatingORI = r.OriginatingORI,
.ReportType = r.ReportType,
.StatusID = r.StatusID,
.SubmittedBy = r.Username,
.ReportDate = r.YearMonthDate,
.ReportDateString = r.YearMonth,
.OccurrenceDate = r.OccurrenceDate
}).ToList()
Have you tried this:
submissionDetails = (From r In model.NIBRS_ReportStatusByORI
Where (sCritera.ORI.Contains(r.OriginatingORI) _
And Not r.ReportType = "ZERO REPORT" _
And r.OccurrenceDate >= sCritera.BeginDate _
And r.OccurrenceDate <= sCritera.EndDate _
And (r.ActionCode <> "D"))
Select New ReportStatusDetails() With {
.ChangeDate = r.Insertdate,
.IncidentId = r.IncidentID,
.IncidentIdentifier = r.IncidentIdentifier,
.OriginatingORI = r.OriginatingORI,
.ReportType = r.ReportType,
.StatusID = r.StatusID,
.SubmittedBy = r.Username,
.ReportDate = r.YearMonthDate,
.ReportDateString = r.YearMonth,
.OccurrenceDate = r.OccurrenceDate
}).Union(From r In model.NIBRS_ReportStatusByORI
Where (sCritera.ORI.Contains(r.OriginatingORI) _
And r.ReportType.Equals("ZERO REPORT") _
And r.YearMonthDate >= sCritera.BeginDate _
And r.YearMonthDate <= sCritera.EndDate _
And (r.ActionCode <> "D"))
Select New ReportStatusDetails() With {
.ChangeDate = r.Insertdate,
.IncidentId = r.IncidentID,
.IncidentIdentifier = r.IncidentIdentifier,
.OriginatingORI = r.OriginatingORI,
.ReportType = r.ReportType,
.StatusID = r.StatusID,
.SubmittedBy = r.Username,
.ReportDate = r.YearMonthDate,
.ReportDateString = r.YearMonth,
.OccurrenceDate = r.OccurrenceDate
}).ToList()
I have written a custom VBA function that will work when I call it from within VBA. e.g.
Sub test()
Debug.Print calculate_acr_bands_data("recommended_acr", "22/11/2014", 2.67, "B23:C27", 50, 2.14, 1, 0.107, 3.89, "22/02/2021")
End Sub
Outputs ...
0.01
However, when I call the exact same function from within a cell in my excel workbook. I get the error "A value used in this formula is of the wrong data type". Which makes no sense because I just proved the formula worked with the exact same inputs from within VBA.
I have uploaded my repo to my GitHub account if you would like to view the source code...
https://github.com/Joshua-W-Adams/vba-wall-loss-vs-time
Thanks for the help.
UPDATE
Function has been posted below...
'Description: Calculate database of wall loss vs time information so relevant parameters can be returned
Public Function calculate_acr_bands_data(return_parameter As String, last_inspection_date As Date, last_inspection_date_wall_loss As Double, _
acr_bands_array_text As String, nominal_wall_thickness As Double, _
minimum_allowable_wall_thickness As Double, current_acr As Double, actual_cr As Double, current_rl As Double, current_end_of_life As Date) As Variant
'Create copy of data range so nominal wall thickness value is not overriden
Dim acr_bands_array As Range: Set acr_bands_array = ThisWorkbook.Worksheets("Wall_Loss_Vs_Time_Graph").Range(acr_bands_array_text)
Dim n As Integer: n = 0
Dim acr_bands_array_size As Integer: acr_bands_array_size = acr_bands_array.Rows.Count
Dim return_data_array() As BAND_ARRAY_CLASS
Dim current_band_position As Integer
Dim recommended_acr As Double
Dim recommended_rl As Double
Dim forecast_wall_loss As Double
Dim recommended_end_of_life As Date
'Update band array with fail FFS wall thickness of current cml
acr_bands_array(acr_bands_array.Rows.Count, 1) = nominal_wall_thickness - minimum_allowable_wall_thickness
'Determine current band that the last inspection date wall loss falls into
For n = 1 To acr_bands_array_size - 1
If last_inspection_date_wall_loss < acr_bands_array(n + 1, 1) Then
current_band_position = n
Exit For
End If
Next n
'Push first row to array (last inspection date details)
return_data_array = push_to_array(return_data_array, "Band Data Points", Format(last_inspection_date, "Short Date"), last_inspection_date_wall_loss, acr_bands_array(current_band_position, 2))
'Debug.Print return_data_array(0).graph_name
'Debug.Print return_data_array(0).date_value
'Debug.Print return_data_array(0).wall_loss
'Debug.Print return_data_array(0).acr
'Push all corrosion rate band data
If n <> 0 Then 'If a hole out is not detected
For n = current_band_position To acr_bands_array_size - 1
return_data_array = push_to_array(return_data_array, _
"Band Data Points", _
Format(DateAdd("d", (acr_bands_array(n + 1, 1) - return_data_array(UBound(return_data_array)).wall_loss) / acr_bands_array(n, 2) * 365, return_data_array(UBound(return_data_array)).date_value), "Short Date"), _
acr_bands_array(n + 1, 1), _
acr_bands_array(n, 2))
Next n
End If
'Push data for current wall loss as of today
For n = 1 To UBound(return_data_array) - 1
If Now() < return_data_array(n + 1).date_value Then
return_data_array = push_to_array(return_data_array, _
"Band Data Points", _
Format(Now(), "Short Date"), _
return_data_array(n).acr * DateDiff("d", return_data_array(n).date_value, Now()) / 365 + return_data_array(n).wall_loss, _
return_data_array(n).acr)
'Dim rsize As Integer
'rsize = UBound(return_data_array)
'Debug.Print return_data_array(rsize).graph_name
'Debug.Print return_data_array(rsize).date_value
'Debug.Print return_data_array(rsize).wall_loss
'Debug.Print return_data_array(rsize).acr
Exit For
End If
Next n
recommended_acr = (return_data_array(UBound(return_data_array) - 1).wall_loss - return_data_array(UBound(return_data_array)).wall_loss) _
/ (return_data_array(UBound(return_data_array) - 1).date_value - return_data_array(UBound(return_data_array)).date_value)
forecast_wall_loss = return_data_array(UBound(return_data_array)).wall_loss
recommended_end_of_life = return_data_array(UBound(return_data_array) - 1).date_value
recommended_rl = DateDiff("d", return_data_array(UBound(return_data_array) - 1).date_value, Now()) / 365
Debug.Print recommended_acr
Debug.Print forecast_wall_loss
Debug.Print recommended_end_of_life
Debug.Print recommended_rl
'Debug.Print recommended_rl
'Add additional graph data for reference
return_data_array = push_to_array(return_data_array, "Today", DateValue(Format(Now(), "Short Date")), 0, 0)
return_data_array = push_to_array(return_data_array, "Today", DateValue(Format(Now(), "Short Date")), nominal_wall_thickness, 0)
return_data_array = push_to_array(return_data_array, "Recommended RL", DateValue(Format(recommended_end_of_life, "Short Date")), 0, 0)
return_data_array = push_to_array(return_data_array, "Recommended RL", DateValue(Format(recommended_end_of_life, "Short Date")), nominal_wall_thickness - minimum_allowable_wall_thickness, 0)
return_data_array = push_to_array(return_data_array, "Recommended ACR", DateValue(Format(Now(), "Short Date")), forecast_wall_loss, recommended_acr)
return_data_array = push_to_array(return_data_array, "Recommended ACR", DateValue(Format(recommended_end_of_life, "Short Date")), nominal_wall_thickness - minimum_allowable_wall_thickness, 0)
return_data_array = push_to_array(return_data_array, "Current RL", current_end_of_life, 0, 0)
return_data_array = push_to_array(return_data_array, "Current RL", current_end_of_life, nominal_wall_thickness, 0)
return_data_array = push_to_array(return_data_array, "Current ACR", DateValue(Format(last_inspection_date, "Short Date")), last_inspection_date_wall_loss, current_acr)
return_data_array = push_to_array(return_data_array, "Current ACR", DateValue(Format(current_end_of_life, "Short Date")), nominal_wall_thickness, current_acr)
return_data_array = push_to_array(return_data_array, "Actual CR", DateValue(Format(last_inspection_date, "Short Date")), last_inspection_date_wall_loss, actual_cr)
return_data_array = push_to_array(return_data_array, "Actual CR", DateAdd("d", (nominal_wall_thickness - last_inspection_date_wall_loss) / actual_cr * 365, last_inspection_date), nominal_wall_thickness, 0)
return_data_array = push_to_array(return_data_array, "Actual RL", DateAdd("d", (nominal_wall_thickness - last_inspection_date_wall_loss) / actual_cr * 365, last_inspection_date), 0, 0)
return_data_array = push_to_array(return_data_array, "Actual RL", DateAdd("d", (nominal_wall_thickness - last_inspection_date_wall_loss) / actual_cr * 365, last_inspection_date), nominal_wall_thickness, 0)
return_data_array = push_to_array(return_data_array, "Fail FFS", DateValue(Format(last_inspection_date, "Short Date")), nominal_wall_thickness - minimum_allowable_wall_thickness, 0)
return_data_array = push_to_array(return_data_array, "Fail FFS", IIf(recommended_end_of_life > current_end_of_life, recommended_end_of_life, current_end_of_life), nominal_wall_thickness - minimum_allowable_wall_thickness, 0)
return_data_array = push_to_array(return_data_array, "Nominal Wt", last_inspection_date, nominal_wall_thickness, 0)
return_data_array = push_to_array(return_data_array, "Nominal Wt", IIf(recommended_end_of_life > current_end_of_life, recommended_end_of_life, current_end_of_life), nominal_wall_thickness, 0)
'Return requested parameter to user
If return_parameter = "database" Then
calculate_acr_bands_data = return_data_array
ElseIf return_parameter = "recommended_acr" Then
calculate_acr_bands_data = Round(recommended_acr, 2)
ElseIf return_parameter = "forecast_wall_loss" Then
calculate_acr_bands_data = Round(forecast_wall_loss, 2)
ElseIf return_parameter = "recommended_rl" Then
calculate_acr_bands_data = Round(recommended_rl, 2)
Else
calculate_acr_bands_data = Null
End If
End Function
'Description: Pass array and values to push
Function push_to_array(bands_array As Variant, graph_name As String, date_value As Date, wall_loss As Double, acr As Double) As Variant
Dim size As Integer: size = UBound(bands_array) + 1
ReDim Preserve bands_array(size)
Set bands_array(size) = New BAND_ARRAY_CLASS
With bands_array(size)
.graph_name = graph_name
.wall_loss = wall_loss
.date_value = date_value
.acr = acr
End With
push_to_array = bands_array
End Function
Your code won't work as a UDF because a UDF can't assign a value to any cell other than the one that the UDF is called from (and its value is assigned by setting the return value of the function).
So, because your line
acr_bands_array(acr_bands_array.Rows.Count, 1) = nominal_wall_thickness - minimum_allowable_wall_thickness
is attempting to modify the state of the Excel worksheet, it will crash and should return a #VALUE! error to the cell the function was called from.
I'm not sure why you are getting a "A value used in this formula is of the wrong data type" error - it is very unusual for a UDF to return any sort of error message, just the error value.
I have a problem with calculating difference between 2 dates where first is older than second.
For example: I want to find difference between
5.5.2015 and 1.11.2014
I used function
=IF((A(DATEDIF(B12,$W$3,"M")<=12,RANK(Q12,Q:Q)<=11)),Q12;0)
but the function is limited only to situations where the second date is higher than the first one.
I want to know whether B12 is within last 12 months from given date. If it is, then I want to calculate with it.
Is there any way to calculate backwards in excel or VBA?
Thank you.
I know this is an old post already but for anyone who needs this...
Function FindDateDiff(myDate1 As Date, myDate2 As Date) As String
Dim myYears As Long, myMonths As Long, myDays As Long
Dim yearString As String, monthString As String, dayString As String, FinalString As String
If myDate1 > myDate2 Then
myYears = Year(myDate1) - Year(myDate2)
myMonths = Month(myDate1) - Month(myDate2)
myDays = Day(myDate1) - Day(myDate2)
If myDays < 0 Then
myMonths = myMonths - 1
myDays = Day(WorksheetFunction.EoMonth(myDate1, 0)) - Abs(myDays) - 1
End If
Else
myYears = Year(myDate2) - Year(myDate1)
myMonths = Month(myDate2) - Month(myDate1)
myDays = Day(myDate2) - Day(myDate1)
If myDays < 0 Then
myMonths = myMonths - 1
myDays = Day(WorksheetFunction.EoMonth(myDate2, 0)) - Abs(myDays) - 1
End If
End If
If myMonths < 0 Then
myYears = myYears - 1
myMonths = 12 - Abs(myMonths)
End If
If myYears = 0 Then
yearString = ""
ElseIf myYears = 1 Then
yearString = myYears & " year, "
ElseIf myYears > 1 Then
yearString = myYears & " years, "
End If
If myMonths = 0 Then
monthString = ""
ElseIf myMonths = 1 Then
monthString = myMonths & " month, "
ElseIf myMonths > 1 Then
monthString = myMonths & " months, "
End If
If myDays = 0 Then
dayString = ""
ElseIf myDays = 1 Then
dayString = myDays & " day"
ElseIf myDays > 1 Then
dayString = myDays & " days"
End If
FinalString = yearString & monthString & dayString
If Right(FinalString, 2) = ", " Then FinalString = Left(FinalString, Len(FinalString) - 2)
FindDateDiff= FinalString
End Function
Just paste this function in a new module in the workbook and you can start calling this function. '=FindDateDiff(A1,B1)'
This function only require 2 dates as arguments and the order doesn't matter.
I've tested this function with both UK and US format, both works exactly the same.
I used DateDiff before, but the calculation for days and months returns an incorrect value and could be very confuse sometimes.
In VBA use the same function.
NoOfDays = DateDiff("D", DATE1, DATE2)
NoOfDays returns either positive or negative value depending on the dates
I have it solved by using ISERROR
=IF(ISERROR(DATEDIF(RC[-16],R3C23,""M"")<=12),0,RC[-1])
Found a function on Excelguru which I changed a few things in and gonna edit some more. The idea is to use this to register worked hours and minutes.
There is one thing in this I don't understand: if I type the wrong time in the column reff I get a msg that its wrong, but it wont disappear unless I click it 10 times. I cant see what Im doing wrong. The entire code is posted and Im grateful for any help.
Use his function as part of the formula in the sheet like: TimeValue($E2;$F2;"16:00";"18:00";B2;9;C2)
Function TimeValue(FromTime As String, ToTime As String, StartTime As String, StopTime As String, Optional Weekday As String, Optional Daynr As Integer, Optional Holiday As String)
Dim x As Long
Dim F As Double
Dim T As Double
Dim Start As Double
Dim Stopp As Double
Dim Min As Long
Dim Day As Integer
Dim OverMid As Boolean
Select Case LCase(Weekday)
Case "mandag"
Day = 1
Case "tirsdag"
Day = 2
Case "onsdag"
Day = 3
Case "torsdag"
Day = 4
Case "fredag"
Day = 5
Case "lordag"
Day = 6
Case "sondag"
Day = 7
Case "x"
Day = 8
Case Else
Day = 0
End Select
OverMid = False
If LCase(Holiday) = "x" Then Day = 8
If Len(FromTime) = 0 Or Len(ToTime) = 0 Then
Exit Function
End If
If Len(FromTime) <> 5 Then
MsgBox ("Use format TT:MM - From time is wrong:" & FromTime)
Exit Function
End If
If Len(ToTime) <> 5 Then
MsgBox ("Use format TT:MM - To time is wrong:" & ToTime)
Exit Function
End If
F = Val(Left(FromTime, 2)) * 60 + Val(Right(FromTime, 2))
T = Val(Left(ToTime, 2)) * 60 + Val(Right(ToTime, 2))
Start = Val(Left(StartTime, 2)) * 60 + Val(Right(StartTime, 2))
Stopp = Val(Left(StopTime, 2)) * 60 + Val(Right(StopTime, 2))
If T = 0 Then T = 24 * 60
If T < F Then
T = T + 24 * 60
OverMid = True
End If
If Stopp = 0 Then Stopp = 24 * 60
For x = F + 1 To T
If x > Start And x <= Stopp Then
Min = Min + 1
End If
Next x
If OverMid = True Then
For x = 0 To Val(Left(ToTime, 2)) * 60 + Val(Right(ToTime, 2))
If x > Start And x <= Stopp Then
Min = Min + 1
End If
Next x
End If
'If weekday is set, equal to day
If Daynr <> 0 Then
If Daynr <> 9 Then
If Day <> Daynr Then Min = 0
End If
If Daynr = 9 And (Day > 5) Then
Min = 0
End If
End If
TimeValue = Min / 60
End Function
And the sub in the sheets
Private Sub Worksheet_Change(ByVal Target As Range)
Dim streng As String
Dim k As Long
Dim r As Long
k = Target.Column
r = Target.Row
If Cells(1, k) = "P" Then
If Cells(r, k) = "x" Then
Cells(r, 4) = "x"
Else
Cells(r, 4) = ""
End If
End If
End Sub
Message boxes really don't belong in UDFs (VBA functions meant to be used as spreadsheet functions).
Instead of the message box you could use code like:
If Len(FromTime) <> 5 Then
TimeValue = "Error! Use format TT:MM - From time is wrong:" & FromTime
Exit Function
Or perhaps:
If Len(FromTime) <> 5 Then
TimeValue = CVErr(xlErrValue)
Exit Function
This later will cause #VALUE! to display in the cell. Include enough documentation in your spreadsheet so that users can interpret such error values.
I have two lists of class objects (Shifts and Employees) with which I am trying to create a join. I then need a count of the resulting items that match the search criteria.
Below is the code I am using, but because I can't find a way to pass the result back as a specific 'type' it's defaulting to boolean and warning me that this will cause a problem:
' Count Shifts for selected hour where: started before or on this
"hour" AND ends after or during this "hour" and Department = filter
value
intShift = Me.Shifts.LongCount(From myshift In Me.Shifts Join
myEmp In Me.EmployeesList On myshift.EmployeeName Equals myEmp.Name
Where myshift.Description = "Shift" And myshift.DateStart.Hour <=
myHour.Hour And myshift.DateEnd.Hour >= myHour.Hour _
And myshift.DateStart.Date = myDay.Date And myEmp.Department =
strFilter _ Or myshift.Description = "Overtime" And
myshift.DateStart.Hour <= myHour.Hour And myshift.DateEnd.Hour
>= myHour.Hour _
And myshift.DateStart.Date = myDay.Date And myEmp.Department =
strFilter)
The search without a join to the employee list and without the matching employee search filters works perfectly but just unable to combine the two.
I have searched for both linq/lambda and inner join examples, but I can't seem to find one that combines these with the longcount function.
I've tried to put together a minimal scenario based on your snippet.
If you request Count or LongCount directly from the query then the result appears to be as expected.
Dim Shifts() = {
New With {.DateStart = #1/1/2014#,
.DateEnd = #1/2/2014#,
.Description = "Overtime",
.EmployeeName = "Darren"}
}
Dim EmployeesList() = {
New With {.Name = "Darren",
.Department = "SO"}
}
Dim strFilter = "SO"
Dim myHour = #1/1/2014#
Dim myDay = myHour
Dim query =
From myshift In Shifts Join myEmp In EmployeesList _
On myshift.EmployeeName Equals myEmp.Name _
Where myshift.Description = "Shift" _
And myshift.DateStart.Hour <= myHour.Hour _
And myshift.DateEnd.Hour >= myHour.Hour _
And myshift.DateStart.Date = myDay.Date _
And myEmp.Department = strFilter _
Or myshift.Description = "Overtime" _
And myshift.DateStart.Hour <= myHour.Hour _
And myshift.DateEnd.Hour >= myHour.Hour _
And myshift.DateStart.Date = myDay.Date _
And myEmp.Department = strFilter
Console.WriteLine(query.Count)
Console.WriteLine(query.LongCount)