Is there a difference between IsNull(x) and x = ""? - ms-access

In if statements I always have to use if isnull(x) or x = "" then
What is the difference between the two and why doesn't each of them work in some cases?

NULL is the absence of a value*
"" is a zero-length string
Due to implicit conversion - an object that hasn't been populated yet might return true for both cases. However if you were to place a value of "" in there, it would return False for isnull() and True for = ""
*Credit to Comintern for improving the explanation (see comments)

If you do that check, to makes sense x must be a Variant, and Null is not "Nothing". Nothing means Empty and a special check for that exists.
Run this and see:
Dim x As Variant
Debug.Print IsEmpty(x) ' True
Debug.Print IsNull(x) ' False
Debug.Print x = "" ' True
Debug.Print Nz(x) = "" ' True
x = Null
Debug.Print IsEmpty(x) ' False
Debug.Print IsNull(x) ' True
Debug.Print x = "" ' Null
Debug.Print Nz(x) = "" ' True
x = ""
Debug.Print IsEmpty(x) ' False
Debug.Print IsNull(x) ' False
Debug.Print x = "" ' True
Debug.Print Nz(x) = "" ' True

As said by the other answers, null is nothing, "" is an empty string.
To test for both null and empty variables in access VBA, use the following:
If nz([variable], "") = "" Then do stuff
The nz function converts null variables to "" or 0

when I want to check for a null/ empty string
I use
If x & "" <> "" then

isnull means the value is not known while edit: "" means it is zero-length string*
*Credit: #Macro Man.

Related

Access Run time error - '-2147352567

error occurred from "clear Button" there are two field with data type with date& time
Private Sub cmdClear_Click()
Me.SampleCode = ""
Me.ReceivedDate = ""
Me.SampleQuntity = ""
Me.SampleReceivedTime = ""
Me.SampleName = ""
Me.BatchNo = ""
Me.MRANo = ""
Me.Division = ""
Me.SubmittedBy = ""
Me.ReceivedBy = ""
Me.AssignedTo = ""
''focuse on SampleCode txtBox
Me.SampleCode.SetFocus
End Sub
Without any further information to go on it's either:
Your received date can't accept any empty string.
If it can't be Null then set it to something like 01-01-1900.
Any fields that are numeric should be set to Null or 0.
It could be that you've misspelt SampleQuntity. Should it be SampleQuantity?

Access VBA - rs.findfirst using regex validation

Hi all first time post.
I'm running a database that has to check data once imported in. I already use one findfirst that works fine which is just checking length of a string. Next I wanted to find any that didn't match a certain pattern in the same field.
Record set is simply
strSQL = "SELECT * FROM TblOrder ORDER BY ID"
Set rs = CurrentDb.OpenRecordset(strSQL, dbOpenDynaset)
The first find that works is;
rs.FindFirst ("Len(string) > 13")
If rs.NoMatch Then
MsgBox "All good"
Else
Do While Not rs.NoMatch
MsgBox "String over 13 - " & rs.AbsolutePosition + 1
rs.FindNext ("Len(string) > 13")
Loop
rs.FindNext ("Len(string) > 13")
End If
So that one is no problem but the one below is where I can't get it to work;
rs.FindFirst ("Validation(string, ""123\d{10}$"") = False")
If rs.NoMatch Then
MsgBox "All are correct pattern"
Else
Do While Not rs.NoMatch
rs.FindNext (Validation(string, "123\d{10}$") = False)
MsgBox "Must start with 978 - " & rs.AbsolutePosition
Loop
rs.FindNext (Validation(string, "123\d{10}$") = False)
End If
I've tried without quotes like on the findnext lines and with as per the findfirst. Without finds null value for the string and with gets a data type mismatch. The string is a number like 123456789 but stored in table as text. The validation works fine if I look through the recordset one row at a time like below;
If Validation(rs!string, "978\d{10}$") = False Then
but I want to scan the entire column rather than go line by line. Line by line was taking too long.
The validation function code is below;
Function Validation(ByRef StrInput As String, ByVal strPattern As String) As String
Dim regex As Object
Set regex = CreateObject("VBScript.RegExp")
With regex
.Pattern = strPattern
.IgnoreCase = True
.Global = False
.MultiLine = False
End With
If regex.Test(StrInput) = True Then
Validation = True
Else
Validation = False
End If
End Function
Don't worry about this I've fixed it. False needed to be in speech-marks.

create case sensitive login in access 2007 and VB6

I have saved a record in Access 2007 table under the fields username and password.
Now i want to check whether proper case has been entered in the VB6 text boxes to validate the username and password from access table.
Please help me in this regard.
Thank you
Sarfaraz
StrComp may suit:
Sub TestMatch()
'string1 is less than string2 -1
'string1 is equal to string2 0
'string1 is greater than string2 1
'string1 or string2 is Null Null
Debug.Print StrComp("ABC", "AB", vbBinaryCompare) ''= 1
Debug.Print StrComp("ABC", "abc", vbBinaryCompare) ''= -1
Debug.Print StrComp("ABC", "ABC", vbBinaryCompare) ''= 0
Debug.Print StrComp(Null, "ABC", vbBinaryCompare) ''= Null
End Sub
See also : http://support.microsoft.com/kb/209674
You may get some posts which make use of RegEx, not something I really use so this function can help you determine whether two strings match and is case sensitive.
Public Function ExactMatch(varFirst As Variant, varSecond As Variant) As Boolean
Dim inti As Integer
'Initialise to False and amend to True if function passes
ExactMatch = False
'Initial checks before proceeding (Null?, Length mismatch?)
If IsNull(varFirst) And IsNull(varSecond) Then
ExactMatch = True
Exit Function
ElseIf IsNull(varFirst) And Not IsNull(varSecond) Then
Exit Function
ElseIf Not IsNull(varFirst) And IsNull(varSecond) Then
Exit Function
End If
If Len(CStr(varFirst)) <> Len(CStr(varSecond)) Then Exit Function
'Begin
For inti = 1 To Len(CStr(varFirst))
If Asc(Mid(varFirst, inti, 1)) <> Asc(Mid(varSecond, inti, 1)) Then Exit Function
Next
ExactMatch = True
End Function
I see people throwing in all kinds of fancy string comparing code and functions... I am puzzled, why not just compare 2 variables?
Variables strUserName_Entered and strPassword_Entered are entered by user and variables strUserName_DB and strPassword_DB are loaded from DB.
If strUserName_Entered = strUserName_DB AND strPassword_Entered = strPassword_DB Then
' Everything is OK, entered username/password combination is exactly the same as the one from DB
Else
' Username/password combination do not match
End If
If you specifically want to differentiate when user enters the right username/password but in wrong case then you can use this
If strUserName_Entered = strUserName_DB AND strPassword_Entered = strPassword_DB Then
' Everything is OK, entered username/password combination is exactly the same as the one from DB
Else If UCase(strUserName_Entered) = UCase(strUserName_DB) AND UCase(strPassword_Entered) = UCase(strPassword_DB) Then
' Username/password combination match, but at least one or more characters is/are in a wrong case
Else
' Username/password combination do not match (not the case error)
End If
I have the answer finally:
Connection
Set rs = New ADODB.Recordset
Qry = "SELECT Password FROM Login WHERE UserName = '" & Text1.Text & "'"
rs.Open Qry, Con, adOpenDynamic, adLockOptimistic
If Not rs.EOF Then
If rs(0) = Text2.Text Then
msgbox"OK"
exit sub
Else
MsgBox "Invalid Username or Password", vbInformation, "Login..."
End If
Else
MsgBox "Invalid Username or Password", vbInformation, "Login..."
End If
Enjoy coding

Search and replace whole words which can be separated not only by a space

I'm looking for a way to search and replace whole words. The whole words can be separated not only by a space but .,;:/? etc.
I'm looking to do something like this
replace([address], ***--list of separators, like .,;:/?--*** & [replacewhat] & ***--list of separators, like .,;:/?--*** ," " & [replacewith] & " ")
I don't know how to pass a list of separators instead of running a replace function once for each combination of separators (which combined with 300 words I'm replacing would amount to an insane number of queries).
You can do a replacement with a regular expression using a pattern with the \b marker (for the word boundary) before and after the word you want to replace.
Public Function RegExpReplaceWord(ByVal strSource As String, _
ByVal strFind As String, _
ByVal strReplace As String) As String
' Purpose : replace [strFind] with [strReplace] in [strSource]
' Comment : [strFind] can be plain text or a regexp pattern;
' all occurences of [strFind] are replaced
' early binding requires reference to Microsoft VBScript
' Regular Expressions:
'Dim re As RegExp
'Set re = New RegExp
' with late binding, no reference needed:
Dim re As Object
Set re = CreateObject("VBScript.RegExp")
re.Global = True
're.IgnoreCase = True ' <-- case insensitve
re.pattern = "\b" & strFind & "\b"
RegExpReplaceWord = re.Replace(strSource, strReplace)
Set re = Nothing
End Function
As written, the search is case sensitive. If you want case insensitive, enable this line:
re.IgnoreCase = True
In the Immediate window ...
? RegExpReplaceWord("one too three", "too", "two")
one two three
? RegExpReplaceWord("one tool three", "too", "two")
one tool three
? RegExpReplaceWord("one too() three", "too", "two")
one two() three
? RegExpReplaceWord("one too three", "to", "two")
one too three
? RegExpReplaceWord("one too three", "t..", "two")
one two three
... and for your range of delimiters ...
? RegExpReplaceWord("one.too.three", "too", "two")
one.two.three
? RegExpReplaceWord("one,too,three", "too", "two")
one,two,three
? RegExpReplaceWord("one;too;three", "too", "two")
one;two;three
? RegExpReplaceWord("one:too:three", "too", "two")
one:two:three
? RegExpReplaceWord("one/too/three", "too", "two")
one/two/three
? RegExpReplaceWord("one?too?three", "too", "two")
one?two?three
? RegExpReplaceWord("one--too--three", "too", "two")
one--two--three
? RegExpReplaceWord("one***too***three", "too", "two")
one***two***three
Thank you for your answer. It was of great help to me.
However, as the number of iterations of this code increased due to increase in my data size, I realized that this piece of code is slowing down my application. For instance, 10,000 iterations of this code take about 20 seconds.
I was using below code based on your answer:
Function CleanString(ByVal InputString As String, Optional SplWords = "USP|BP|EP|IP|JP", _
Optional Delim As String = "|") As String
Dim i As Integer
Dim ArrIsEmpty As Boolean
Dim ArrSplWords() As String
Dim Wrd As Variant
Dim RE As Object
CleanString = InputString
ArrSplWords = Split(SplWords, Delim)
Set RE = CreateObject("VBScript.RegExp")
RE.Global = True
RE.ignorecase = True
For Each Wrd In ArrSplWords
RE.Pattern = "\b" & Wrd & "\b"
If RE.test(CleanString) Then
CleanString = RE.Replace(CleanString, "")
End If
Next Wrd
CleanString = Application.WorksheetFunction.Trim(CleanString)
End Function
To tackle the issue of slowness, I decided to ditch the RegExp approach and came up with below code. Based on my evaluation, the below function is about 25 times faster (I timed it using timer function over 1000 iterations of each code).
Function CleanString(ByVal InputString As String, Optional SplWords As String = "USP|BP|EP|IP|JP", _
Optional Delim As String = "|", Optional WordSeparator As String = " ", _
Optional SplChar As String = "~|`|!|#|#|$|%|^|&|*|-|+|=|'|<|>|,|.|/|\|?|:|;") As String
Dim TestStr As String
Dim ArrSplChar() As String
Dim Char As Variant
Dim TestWords() As String
Dim Wrd As Variant
Dim Counter As Integer
TestStr = InputString
ArrSplChar = Split(SplChar, Delim, -1, vbTextCompare)
For Each Char In ArrSplChar
TestStr = Replace(TestStr, Char, WordSeparator & Char & WordSeparator, 1, -1, vbTextCompare)
Next Char
TestWords = Split(TestStr, WordSeparator, -1, vbTextCompare)
For Each Wrd In TestWords
Counter = IIf(Wrd = "", Counter + 1, Counter)
If InStr(1, LCase(SplWords), LCase(Wrd), vbTextCompare) = 0 Then
CleanString = CleanString & " " & Wrd
Counter = Counter + 1
End If
Next Wrd
CleanString = IIf(Counter - 1 = UBound(TestWords) - LBound(TestWords), _
Application.WorksheetFunction.Trim(InputString), _
Application.WorksheetFunction.Trim(CleanString))
End Function
This function looks a little messier than the regExp based function, but it is faster than the regExp based function.
Both the above functions generate the same output and can be called as follows:
Sub TestSub()
Debug.Print CleanString("Paracetamol USP")
End Sub
This will print "Paracetamol" in the immediate window.

Proper way to check if an unbound control has a value

Simple scenario: a form and one text box (unbound), Text1.
If "" <> Text1 Then
MsgBox "Not Empty"
End If
The above code works. The expression ""<> Text1 evaluates to True if the text box contain characters.
The opposite doesn't work, regardless of the text box is empty or not:
If "" = Text1 Then ' or alternatively, False = ("" <> Text1)
MsgBox "Empty!"
End If
Can you clarify this issue?
The textbox is usually null if it does not contain anything, this is not the same as a zero length string (""). It can often be best to use:
If Trim(Text1 & "") = vbNullString
'Empty
This will be true if the textbox contains spaces, a zero length string or null.
Alternatively, I've got a small function that I find useful for checking that sort of thing when dealing with various variable types and I just want to know whether it's blank.
'-----------------------------------------------------------------------------'
' True if the argument is Nothing, Null, Empty, Missing or an empty string. '
'-----------------------------------------------------------------------------'
Public Function IsBlank(arg As Variant) As Boolean
Select Case VarType(arg)
Case vbEmpty
IsBlank = True
Case vbNull
IsBlank = True
Case vbString
IsBlank = (arg = vbNullString)
Case vbObject
IsBlank = (arg Is Nothing)
Case Else
IsBlank = IsMissing(arg)
End Select
End Function
Just Made a blog post today about it too.
I always use the function Nz (variable, valueIfNull) to check those kind of things. For example:
if (Len(Nz(Me.txt1, "")) > 0) then
'Me.txt1 does not contain a value
end if
Or if I want to save a textbox's value to a recordset:
rst!Name = Nz(Me.txtName, "No name given")