IIF false expression impacting truthiness? - vb.net

I am developing an SSRS tablix report and struggling to remove some error messages from certain cells. The Expression in the cell is as follows:
=Iif(IsNothing(First(Fields!Details.Value)) , "", Join(Code.RemoveDuplicates(LookupSet(Fields!studyTitle.Value, Fields!studyTitle.Value, Fields!Link.Value ,"DataSet1")), vbCrLf ))
The custom function that's referenced is as follows:
Public Shared Function RemoveDuplicates(ByVal items As Object()) As String()
System.Array.Sort(items)
Dim k As Integer = 0
For i As Integer = 0 To items.Length - 1
If i > 0 AndAlso items(i).Equals(items(i - 1)) Then
Continue For
End If
items(k) = items(i)
k += 1
Next
Dim unique As [String]() = New [String](k - 1) {}
System.Array.Copy(items, 0, unique, 0, k)
Return unique
End Function
The problem I'm encountering is that cells in the output will display "#ERROR" if they are being run through the custom function with multiple blank values.
The goal of the initial IIF statement is to test those rows first to make sure that the function is only applied to those rows that have values, and the other cells should just be blank. The problem is that I'm still seeing errors for those cells, as if the false condition is applied anyway.
However, if I edit my IIF statement to have the same test condition but different true-part and false-part i.e.:
Iif(IsNothing(First(Details.Value)), "true", "false"))
Then suddenly I see exactly the rows I would expect to see marked true and false. If this is the case then I can't figure out where the errors are coming from in my initial statement.
I know the issue has to be somewhere with the RemoveDuplicates function because when I take that part out and just Join my duplicated values then I see no errors, and the false rows are the same as identified above.
Does anyone see something I'm missing that is generating this error or causing this seemingly inconsistent behavior from the IIf function?

Use If instead of IIf. The If construct shortcuts the evaluation, while the IIf evaluates all expressions.
=If(IsNothing(First(Fields!Details.Value)) , "", Join(Code.RemoveDuplicates(LookupSet(Fields!studyTitle.Value, Fields!studyTitle.Value, Fields!Link.Value ,"DataSet1")), vbCrLf ))
This is only available in VB.net and is not available in VBA. In VBA, you would use a standard If-Then-Else construct.

Related

Variable in Dlookup in Access 2016 returns runtime error 13 - type mismatch

The logic isn't complex. The application uses a temporary table into which data for a report is appended. Once the report has been run, the data is cleared. Initially, the client told me that he would enter all the data (by taking attendance of people attending an event) would be done at once. Now, that has changed. I lookup the max ID in the temp table - if the number of rows is greater than 0. I then want to use dlookup to let the client know where she left off lest they create more problems.
Here's the logic:
Dim VMax As Variant
Dim VNFind As String
VMax = DMax("foodpantryid", "signin_sheet_data") 'This works correctly
MsgBox VMax 'This works correctly
VNFind = DLookup("last_name", "Dat_household_member", "[household_id]" = VMax) 'I get the type mismatch/error 13 here.
MsgBox VNFind 'so this never works
Additional information:
Household_id is a long integer. When I change it to integer, I get an error 94 (invalid use of null).
I have tried setting VMax to variant, integer, and long. Still no success. I would think variant would have worked.
The DLookup works if I don't include "[household_id]" = VMax.
I've tried including the =VMax in "" and that fails as well. That produces a 2471 error.
You've put your = outside the string delimiters.
This means: say your ID is 5. Then the parameter is "[household_id]" = 5. That's a comparison between the string "[household_id]" and the number 5, which causes a type mismatch, because you can't compare strings to numbers unless the string can be cast to a number.
Instead, you should include the = in your string, and the DLookUp should be:
DLookup("last_name", "Dat_household_member", "[household_id] = " & VMax)
Or, better yet, use parameters. This avoids most typecasting and string concatenation errors.
TempVars!VMax = VMax
DLookup("last_name", "Dat_household_member", "[household_id] = TempVars!VMax")
TempVars.Remove "VMax"

What am I missing in this IsEmpty clause?

In an Excel VBA module I'm building, I have some code to execute if a table of out-of-gauge cargo contains anything. I initially wrote this:
If Not IsEmpty(Range("OOGData")) Then
...
Else
...
End If
But even when OOGData is empty, it keeps returning False. I've tried it with If IsEmpty(Range("OOGData")) = False Then` but that doesn't seem to make any difference. My current code is
If IsEmpty(Range("OOGData")) = False Then
...but that still activates with the empty range.
I've made sure there are no formulae, hidden values or anything that could be showing up.
Any idea what the problem could be?
According to this information:
Returns a Boolean value indicating whether a variable has been
initialized.
In your code you are not working with variable therefore you shouldn't expect correct value.
When checking single cell you should use Len() function instead:
If Len(Range("OOGData"))=0 Then
'cell is empty
When checking if range of cells is empty use this solution:
If WorksheetFunction.CountA(Range("OOGData"))=0 Then
'rabge is empty
The final alternative I can think of is to use loops.
I've decided to cheat. Instead of checking the list there, I've added a Boolean variable (bContainsOOG) that's set to True any time an OOG cargo item is added to the OOG list, and then the reporting sub checks against that instead. But thanks both of you for those suggestions, they'll come in handy in another bit I was getting stuck on. :-)
This is a function that I thinks very closely fits:-
' Function to determine the last (first blank/null/empty) cell in a series of data in either a column
' or row
' Usage :- DataSeriesEnd(w,r,b)
' where w is the name of the worksheet.
' r is the row or column as an integer
' b is a boolean (true/false) if true then processing a column, if false a row
Public Function DataSeriesEnd(Worksheet As String, rc_index As Integer, bycolumn As Boolean) As Integer
Dim cv As Variant
For DataSeriesEnd = 1 To 500
If bycolumn Then
cv = Worksheets(Worksheet).Cells(DataSeriesEnd, rc_index)
Else
cv = Worksheets(Worksheet).Cells(rc_index, DataSeriesEnd)
End If
If IsNull(cv) Or IsEmpty(cv) Or cv = "" Then Exit For
Next DataSeriesEnd
' Position to previous cell (i.e. this one is empty)
DataSeriesEnd = DataSeriesEnd - 1
End Function
Note! There is a limit of 500 rows/columns

Select case among different checkboxes inside frame - Userform issue

I have putted several checkboxes in a frame and I need to make an select case statement among these checkboxes. Is there a way to select the checkboxes which are within the frame through a select case statement?
I have tried it below ( my frame is named diet_frame ) but I get a type mismatch error.
Private Sub add_button_Click()
Dim target_range As Range: Set target_range = Range("A2:G29")
Dim period As String
target_range.End(xlDown).Offset(1, 0).Select
With Selection: i = 1
Selection.Value = name_input
Selection.Offset(0, i) = period_input.Value
Select Case diet_frame <<<--- name of my frame, trying to get to the checkboxes placed inside it.
Case meat_input.Value = True
Selection.Offset(0, i + 1) = carnivore
Case vegetation_input.Value = True
Selection.Offset(0, i + 1) = herbivore
Case vegetation_input = True And meat_input = True
Selection.Offset(0, i + 1) = omnivore
End Select
Selection.Offset(0, i + 6) = group_input.Value
End With
Frames are usually used to group option (radio) buttons, to make them mutually exclusive. I don't think they provide the functionality you expect. You need to be explicit about a few things: Where are name_input, period_input, group_input coming from? If those are cells I expect to see some "RangeRefersTo". Do you have a single set of checkboxes or many sets aligned with these many rows of the Selection object? Programmatically generated or manually (and left as-is for the life of workbook)? You might have meant a "ForEach ... in Selection" rather than a "With"? The With is not going to iterate through cells for you. By the way, you aren't incrementing your "i" column-number so why not just hard-code the 1, 2, and 7? If you have lots of static checkboxes use the tag property to store the row number associated with them. That is a way to tie them to specific cells if you don't have bound-cells for them. If you have lots of boxes and bound-cells then you can't re-use the 3 names for them without going to some extra trouble. You want to poll a bunch of checkboxes?
(quite possibly pseudocode)
Dim ctrl as control
For Each ctrl in controls
If ctrl.typeof = "checkbox" then
'maybe further specificity based on If ctrl.name = "somename" ...
' more code...
cells(ctrl.tag,7).value2 = whatever
End if
As far as your "Select", your code will run as-is if you just put Select Case True (weird but it works) but for Omnivores you're setting the value 3 times. Actuall you don't even need VBA. You can do all this with cell formulas. Put 1 for true in bound cell for meat, 2 for veggie. Put a sum of them in an IF or CHOOSE formula in the target cell (where "...vore" will appear). So 1 is Carnie, 2 is Veggie, 3 is Omni. On a Gnu/Linux box or I'd be more explicit.
The help says that
the select case statement requires a numeric or string expression - ie an expression which result can be evaluated as a number or a string via the play of automatic conversions. So strictly on the form, and unless the Frame object default property actually returned a numeric or string expression, you're going to get a type mismatch error there with your code
the result of the expression from the select case statement is going to be matched against the result of the expressions for the different Case clauses - so these expressions need to be type compatible as well
Try and use the True keyword as your expression for the select case statement - booleans are automatically convertible to both numbers and strings -, and the values of your checkboxes for each Case clauses. This would also require for you to move the case where both your checkboxes are True to the first place in your Case hierarchy - reason for this is that when expressions match for more than one Case clause, only the statements following the first match are executed

#VALUE error with Excel VBA Function

In my Excel spreadsheet I have two columns.
A contains strings with the values 'Yes', 'No' or 'Maybe'.
B contains strings with a year in.
I need a function to determine the number of occurrences of a year in column B, where the equivalent value in column A is 'Yes'.
I currently have the following code:
Function CountIfYearAndValue(Rng As Range, YNM As String, Year As String) As Integer
Dim count As Integer
count = 0
For Each c In Rng.Cells
If (StrComp(Abs(c.Value), Year, vbTextCompare) = 0) And (StrComp(Cells(c.Row, A), YMN, vbTextCompare) = 0) Then count = count + 1
Next
CountIfYearAndValue = count
End Function
The idea of this code is that we iterate through every cell in the range given (a range on column B) and check if the year is equal to the Year parameter. And if the equivalent cell on column A is equal to the YNM parameter we increment the count variable.
For some reason this code does not work when I use the following parameter:
=CountIfYearAndValue('Years'!B1:B7,"Yes","Year 7")
It just does the #VALUE error and refuses to display any outcome.
Any help would be much appreciated.
Edit: All of the values in both cells are on of an unformatted datatype ('General') and no cells are blank.
It sounds like you are reinventing the wheel... There already is a built in function (advantage: being much faster than a UDF) that does exactly what you are after. It is called COUNTIFS()
All YESes for Year 7 in rows 1 to 10.
=COUNTIFS(B1:B10, "Year 7",A1:A10, "Yes")
I just had a quick look at your code and I think there are possibly a few reasons why your original code is not working as expected.
YNM is a valid column name therefore it should not be used as a variable name. You should avoid naming your variables like that - give it a more meaningful name
YNM != YMN as you had it in your code (see function definition and then the misspelled version in the StrComp() function)
Year is a valid VBA built in function, therefore once again you should avoid using it as a variable name as you're exposing yourself to a naming collision.
Add Option Explicit at the top of your module. This requires you to Dimension all you variables. It's always recommended for many many reasons.
rng variable is of Range type therefore you do not need to explicitly add the .Cells property to it. Even though it may help in some cases - at a bit more advanced level you may face some runtime type compatibility issues. ( runtime may convert your rng Range variable to a 2D array etc )
Added an explicit conversion in the second StrComp() function around the c.Offset(0, -1) as you don't want the runtime to (rare but still possible) convert your Yes to a Boolean data type. Explicit conversion to a String just gives you that extra protection ;p (lol)
therefore, something like this returns the correct value
Function CountIfYearAndValue(rng As Range, choice As String, myYear As String) As Long
Dim count As Long
count = 0
Dim c As Range
For Each c In rng
If (StrComp(c, myYear, vbTextCompare) = 0) And (StrComp(CStr(c.Offset(0, -1)), choice, vbTextCompare) = 0) Then
count = count + 1
End If
Next c
CountIfYearAndValue = count
End Function
Right, I hope this helps you understand bits and pieces :) any questions please leave a comment

rdlc skip hidden rows on condition

I know this may sound trivial but I just can't find an answer to it.
I have a rdlc report in which I like to alternate row background color and for this I've used the following formula:
=iif(RowNumber(Nothing) Mod 2, "#e5e5e5", "White")
I also need to hide some rows and for this I use the following formula:
= Fields!MeanAeb.Value <> ""
where MeanAeb is a field in my report. My problem is that rowNumber also counts the hidden rows, so my table may have two consecutive rows with the same background. is there a way to take only visible rows into account?
So if anyone has the same problem, I have an answer;
in the Code section of your ReportProperties add the following
Dim customRowNumber as Integer = 0
Dim previousRowNumber as integer = 0
Function CustomRowCounter(conditionToTest as Boolean, rowNumbner as Integer) as Integer
if(conditionToTest and rowNumbner <> previousRowNumber)
customRowNumber = customRowNumber + 1
previousRowNumber = rowNumbner
end if
return customRowNumber
End Function
then on the background field in your column properties add this condition:
=iif(Code.CustomRowCounter(Fields!MeanAeb.Value="",RowNumber(nothing)) Mod 2, "#e5e5e5", "White")
this is nice because you can add any condition you like in place of Fields!MeanAeb.Value="". Just remember to use the inverse of the condition in your rowVisibility field, otherwise you may cause strange effects.
Oh and if you want a chess board look to your report just drop the previousRowNumber :)