Handling NULL = NULL comparisons in Access VBA - ms-access

I have a problem with NULL = NULL returning NULL. I want it to return True. After a bit of research I found a line that I thought would work..
set ansi_nulls off
I quickly learned that Access doesn't recognize it. So here I am attempting to do nested conditions in Access and it's a complete nightmare.
Is there an easier way to handle this?

If you're doing a large amount of "equal or both null" comparisons, there are multiple solutions:
If you're OK with 0 = Null resulting to true when comparing numbers, or "" = Null resulting to true when comparing strings, you can use:
If Nz(Value1) = Nz(Value2) Then
This replaces all Nulls with 0 or "" dependent on the input type.
Consequences: Nz(Null) = Nz(Null) → True, 0 = Nz(Null) → True, "" = Nz(Null) → True, 1 = Nz(Null) → False, "a" = Nz(Null) → False
Create a user-defined function to do the comparison for you
The function:
Public Function CompareWithNulls(Value1 As Variant, Value2 As Variant) As Boolean
If IsNull(Value1) And IsNull(Value2) Then
CompareWithNulls = True
Else
CompareWithNulls = Value1 = Value2
End If
End Function
The use of the function:
If CompareWithNulls(Value1, Value2) Then

You can use the And keyword to test multiple conditions without nesting:
If IsNull(Value1) And IsNull(Value2) Then
You could create a method to compare two variables with a null check and then each IF only needs to call this function instead of the usual =

Related

SSRS Iif Evaluates True and False

MSDN states that SSRS will evaluate both the true and false part of an Iif statement regardless of which one is returned. This seems to make Iif completely useless in regard to error avoidance. In other words, you cannot use Iif to skirt around an error, so essentially any operation you choose to include must always be valid regardless of the conditions. Honestly, what good is this?
So my question is... Does SSRS have other ways of evaluating conditions besides Iif?
Here is my example. I just want to be able to return Left without grabbing the first character of the match.
=Iif
(
InStr(Fields!SearchField.Value, Fields!Criteria.Value) <= 1,
"",
Left(Fields!SearchField.Value, InStr(Fields!SearchField.Value, Fields!Criteria.Value)-1)
)
However, what is happening here is that InStr(Fields!Criteria.Value, Fields!Criteria.Value)-1 is evaluating to 0 in some cases, which is perfectly fine until the FALSE part of the statement tries to deduct 1 from it and pass it into the InStr function. InStr cannot accept -1 as the number of characters to return.
An oversimplification of this is as follows. Assume you have a situation where Value can never fall below 0 without throwing an error.
Iif (Value > 0, Value = Value -1, 0)
Trying to use Iif to force the value not to fall below 0 does not work because all of these statements get evaluated even if they do not meet the conditions.
Trying to use InStr to get an index on a match, and Left to build a substring based on that index fails because of this. I have no idea how to completely avoid the condition.
I too thought Switch would work, but upon testing it did not. As far as I can tell, custom code is the only way to go. I tested the function below which worked for my few test cases.
Public Function TruncateWord(ByVal str As String, ByVal criteria As String) As String
If str.Contains(criteria) Then
Return Left(str, InStr(str, criteria) - 1)
Else:
Return ""
End If
End Function
I tested with the below 5 basic strings, searching for "d", and got the following results:
+-----------------+
| String | Result |
+-----------------+
| asdf | as |
| asd | as |
| as | |
| da | |
| ad | a |
+-----------------+
So this appears to work for all 3 possible cases (InStr returns > 1, InStr returns 1, and InStr returns 0) from my limited testing.
Here is the final result from C Black's suggestion to use custom code. I had eventually hoped to use the segment of the string to format the match in a different color in the opposite column. I had to add some html tags. It works perfectly. Thank you all for your assistance.
Code block:
Public Function ParseMatch (ByVal FullString As String, ByVal Criteria As String) As String
Dim Segment(2) As String
Dim Result As String
If FullString.ToUpper.Contains(Criteria.ToUpper)
Segment(0) = Left(FullString, InStr(Ucase(FullString), Ucase(Criteria) )-1 )
Segment(1) = Criteria
Segment(2) = Right(FullString, Len(FullString) - Len(Segment(0)) - Len(Criteria))
Result = Segment(0) & "<b><FONT color=blue>" & Segment(1) & "</FONT></b>" & Segment(2)
Else
Result = FullString
End If
Return Result
End Function
Report cell:
=Code.ParseMatch(Fields!Defendants.Value, Fields!Firm_Client_Name.Value)
If the name is found in the list of defendants, it colors the text blue in that field and bolds it.
Use SWITCH
SWITCH stops evaluating expression as soon as the first True is found. Switch works with pairs (an expression to evaluate and a result if it's true). The final True acts like an else.
=SWITCH
(
InStr(Fields!SearchField.Value, Fields!Criteria.Value) <= 1, "",
True, Left(Fields!SearchField.Value, InStr(Fields!Criteria.Value, Fields!Criteria.Value)-1)
)
I rewrote it for readability:
=Switch
(
InStr(Fields!Defendants.Value, Fields!Firm_Client_Name.Value) = 0, "",
InStr(Fields!Defendants.Value, Fields!Firm_Client_Name.Value) = 1, "",
True, Left(Fields!Defendants.Value, InStr(Fields!Defendants.Value, Fields!Firm_Client_Name.Value)-1)
)
' 0 = Error
' 1 =
' >1 = substring based on criteria
1 and >1 are correct, but I still get the error when the InStr evaluates to 0.
The thing is, I have to tell the Left function -1 or it will return the first letter of the delimiter, which I do not want. Even though the condition of InStr(Fields!Defendants.Value, Fields!Firm_Client_Name.Value) = 0 is true, instead of returning "" for the column, it returns an error. This tells me it is still being evaluated despite it being outside of the specified condition.
If I omit the -1 within the Left function, no error results. Yet I get substring + first letter of delimiter.
I work with sensitive information, so I cannot give specific results of the strings.

How to prevent specified table content from being altered?

I got this (very simplified) scenario while coding a port handling routine for a micro-controller.
3 files
file1:
table = {var1 = true, var2 = true, var 3 = false, var 4 = true}
function dosomething()
dosomething
--defines bools in table by whatever condition is present
end
file2: Actually a Menu. If an input is given the corresponding boolean in table is changed.
function selection()
selection = interprete_input()
invertVars(selection)
end
function invertVars(selection)
table.selection = not table.selection
end
file3: in the simplified scenario, only uses the bools#table to know it to operate for the given case or not. The indices are used as values as well. For example one entry in table could be ' ["ttyS0"] = true ' so I know the function whether should run for COM-Port ttyS0 or not
function needsVarsFromTable()
for v,k in pairs(table)
if k then
--the actual function uses true/false as indicator to know if to run
--for the entry of table or not.
the_actual_function_that_needs_v(v)
end
end
The Problem now is:
The Table contains 19 entries. 2 of them have to be static. They're false and can never be true. But in my script it's possible to make them true what will cause errors.
Unfortunately Lua doesn't bring static variables. How can I prevent them from be altered by other functions? These other functions still have to be able to read them.
I don't want to check for every var#Table if the reading function is allowed to alter, due performance issue.
PiL 13.4.5 provides an example of read-only table, read the whole chapter if you are not familiar with metatables and metamethods.
To protect the field "var2", a little modification to the code in the book can do it:
local t = {var1 = true, var2 = true, var3 = false, var4 = true}
function protect_field(t)
local proxy = {}
local mt = { -- create metatable
__index = t,
__newindex = function (t, k, v)
if k == 'var2' then
error("attempt to update var2 field")
else
rawset(t, k, v)
end
end
}
setmetatable(proxy, mt)
return proxy
end
t = protect_field(t)
Now it's legal to update field "var1":
t.var1 = false
But t.var2 = false will raise an error.

Combobox null in if statement

I am trying to code an if statement where if a certain combobox is null, then it runs a certain part of code if it has data in it then it runs another. I wrote up this:
Private Sub ProjectAddSetDateAutoBtn_Click()
If ProjectAddAllDueDateAutoCmBx = Null Then
'Code1
Msgbox("ComboBox Is Null")
Else
'Code2
Msgbox("ComboBox Has Data")
End If
End Sub
I leave the combobox with no data, and then it doesn't run the code in the first part of the if or the code in the 2nd part of it either! If I enter data into the box, it runs the 2nd part of the if statement perfectly. There are no errors, I am quite stumped on this. Do ComboBoxes have their own "Null"? Is there a problem with this if statement?
Nothing is ever equal to Null, not even another Null.
Use IsNull() to check whether the combo box is Null.
'If ProjectAddAllDueDateAutoCmBx = Null Then
If IsNull(ProjectAddAllDueDateAutoCmBx) = True Then
I would suggest
If IsNull(ProjectAddAllDueDateAutoCmBx.Value) Then
It correctly checks for Null (IsNull instead of = Null), and it explicitly checks the value of the combo box.
(In most cases -- depending on the context -- just using the name of the control yields the value, but it doesn't hurt to be explicit.)
You cannot use a = Null comparison to get the results you want because Null propagates. To see this in action, try:
? Null = Null
in the Immediate Window and you'll see that Null is returned. Use the IsNull function, which will return true or false as you would expect.
Private Sub ProjectAddSetDateAutoBtn_Click()
If IsNull(ProjectAddAllDueDateAutoCmBx) Then
'Code1
Msgbox("ComboBox Is Null")
Else
'Code2
Msgbox("ComboBox Has Data")
End If
End Sub
While the accepted answer is totally correct, I use a different approach:
If HasValue(ProjectAddAllDueDateAutoCmBx) Then
where the HasValue function is:
Public Function HasValue(v As Variant) As Boolean
If Trim(v & "") <> "" Then
HasValue = True
Else
HasValue = False
End If
End Function
This has the advantage of treating NULL and "" (or any pure whitespace) values the same, which is many times what you want with MSAccess controls. For example entering a value in a null-valued textbox and removing it again with backspace will result in a ""-value, not NULL. From a user-perspective this is mostly meant to be the same.
[The (v & "")-part is just a trick to force conversion to a string.]
the equivalent of null in VB is Nothing so your check wants to be:
If ProjectAddAllDueDateAutoCmBx Is Nothing Then
....
it hope helps.

if ( object != null ) instead of if ( object ) in AS3

Is there any reason to use if ( object != null ) in a conditional instead of the more concise if ( object ). I see the former more often, but it seems like the two are equivalent and the latter shorter.
different objects are treated differently. there are some values that can never be null and might erroneously trigger false when you don't want it to.
Booleans can never be null.
if a Boolean is defined but not given a value it is treated as false;
var bool:Boolean;
trace(bool); // false
bool = true;
trace(bool); // true
int can never be null as well.
if an int is defined but not given a value, it is treated as 0;
var i:int;
trace(i); // 0
trace(Boolean(i)); // false
i = -1;
trace(Boolean(i)); // true
i = 0;
trace(Boolean(i)); // false
i = 1;
trace(Boolean(i)); // true
Number act similar to int.
if a Number is defined but not given a value, it is treated as NaN
var num:Number;
trace(num); // NaN
trace(Boolean(num)); // false
num = -1.1;
trace(Boolean(num)); // true
num = 0;
trace(Boolean(num)); // false
num = 1.1;
trace(Boolean(num)); // true
Strings are the worst.
if a String is defined but not given a value, it is treated as null!
var str:String;
trace(str); // null
trace(Boolean(str)); // false
str = ""
trace(Boolean(str)); // false
str = "hello";
trace(Boolean(str)); // true
it is very rare in my code that i only do 'if (obj)' since most of the time there is something more specific that i truly care about.
The following code will have an object evaluate to false, even though the object is not null:
class SomeWrapper
{
var value: Object;
SomeWrapper(Object value)
{
this.value = value;
}
/// Overriden method from Object, see ActionScript 3 reference
function valueOf()
{
return value;
}
}
var myWrapper = new SomeWrapper(false);
if(myWrapper)
{
trace("myWrapper evaluates to true.");
}
else
{
trace("myWrapper evaluates to false.");
}
The else block will execute in the example above, because myWrapper evaluates to false (its valueOf method returns whatever value the wrapper contained, in this case false) even though myWrapper is not a null reference. The problem is that the above does not only test nullability of reference, it implicitly invokes valueOf method, courtesy of Flash Player virtual machine. This behavior of course may or may not be what you wanted - do you want to test whether myWrapper is a null value or whether it carries a null value? (or both perhaps).
Verbosity in this case is your friend, otherwise you gain code readability in return for potential runtime errors.
if (expression) tests the truthiness of expression by getting its boolean value. Since null and undefined are both falsy, if (object) "works" for making sure object isn't null.
Problem is, though, 0, false, and '' are also falsy. When you use if (object), the code you're trying to keep from running when it's null would also be ignored when object is zero, an empty string, or the actual boolean false. Often, that's not what you want.
If you can't guarantee that object is either null or a type other than string, number, or boolean (or their respective object types), then if (object != null) is less likely to mean something unintended.

Access Vba - To find null and blank values

I am trying to find the blank values and null values in a table. I am using Asc to assign the values of the table to a variable and then based on their ASCII values differentiating null and blank. But I am getting "runtime error 94: Invalid use of null" when the code tries to read the ASCII value of a null field.
When I have to deal with return values that can be either Null or zero-length string, I use a function that converts ZLS to Null:
Public Function varZLStoNull(varInput As Variant) As Variant
If Len(varInput) = 0 Then
varZLStoNull = Null
Else
varZLStoNull = varInput
End If
End Function
This takes advantage of the fact that the VBA Len() function treats a Null and a ZLS exactly the same so that you don't have to handle each case individually.
However, remember that if you use this in a WHERE clause, you'll be losing performance because it can't use the indexes. Thus, in a WHERE clause, you'd test for IS NULL or =""
SELECT MyField
FROM MyTable
WHERE MyField Is Null Or MyField = ""
That will be much more efficient. The varZLSToNull function is most useful when you're appending processed data to a field that has ZLS Allowed set to NO (as it should).
Another thing you should consider is changing your field so that it disallows ZLS, then running a query (using the WHERE clause above without the Is Null) to replace all the ZLS's with Nulls.
Of course, that assumes that your data is not distinguishing between Null and ZLS as meaning two different things (Null meaning "we haven't recorded any value here" and ZLS meaning "we have recorded an empty value here").
You can try the following user-defined function to test the table value:
Public Function text_test(str_in as Variant) As Long
' given input str_in, return -2 if input is Null,
' -1 if input is zero-length string; otherwise return 0
' use function Nz to test if input is Null and return -2,
' otherwise check non-null value with Len
' and return -1 if it is a 0-length string,
' otherwise return 0 for anything else
text_test = IIf(Nz([str_in], "null") = "null", -2, _
IIf(Len(str_in) = 0, -1, 0))
End Function
In the immediate window run a test with different inputs:
?text_test("fred");text_test("");text_test(Null);text_test(9);text_test(False)
Should return:
0 -1 -2 0 0
Note that you cannot use str_in as string in the function declaration since this will cause the same error you refer to in your question.
I think you should be using IsNull() to decide if a value is null.
https://web.archive.org/web/1/http://articles.techrepublic%2ecom%2ecom/5100-10878_11-5034252.html
encapsulate your code inside a if statement and compare the string value to vbNullString like this:
If (Not (<string> = vbNullString) Then
if the string is NOT null execute your original code
if it is null add an Else block to execute what you need to do if the value is null
Yeah, it's an old thread, big deal...
This is the most concise way to test a value for Null and zero-length that I've seen:
FinalValue = IIf(Not Len(Nz(Value, "")) = 0, Value, Null)
How it might perform compared to David Fenton's excellent Function above, I do not know. I do know that the one-liner I present here and David's function do almost exactly the same thing. I suspect the one-liner might perform a bit better than a call out to a Function. On the other hand it makes use of an inclusive If, so it may in fact be slower. Who knows?
I use it in Class modules, mainly. For example, when creating a record with a DAO Recordset:
With rst
.AddNew
!JobCardID = IIf(Not m_JobCardID = 0, m_JobCardID, Null)
!ConstructionProjectID = IIf(Not m_ConstructionProjectID = 0, m_ConstructionProjectID, Null)
!MajorDisciplineID = IIf(Not m_MajorDisciplineID = 0, m_MajorDisciplineID, Null)
!ActivityDescriptorID = IIf(Not m_ActivityDescriptorID = 0, m_ActivityDescriptorID, Null)
!ActivityStatus = IIf(Not Len(Nz(m_ActivityStatus, "")) = 0, m_ActivityStatus, Null
'etc...
End With
In the above code, ActivityStatus is the relevant String.
Note: I never design a database with fields allowing zero-length strings. Repeat: NEVER.