变体是唯一可以存储空值或 Null 值的变量类型,因此声明如下:
Dim aVar as Variant
Dim aVar2 ' if no type is given then it's declared as a variant
变量声明后立即不存储任何值并且它是空的。
您也可以使用aVar = Empty 将空分配给变体,它将再次为空。
当变量存储为空时,这些都是正确的:
aVar = Empty
IsEmpty(aVar)
您还可以将 Variant 变量的值设置为 Null
aVar = Null
现在这些都是假的
aVar = Empty
IsEmpty(aVar)
但是,IsNull(aVar) 是真的。
当您使用 VBA 变量存储来自允许将 NULL 值存储在其字段中的数据库表的数据时,Null 特别有用。在这种情况下,通常建议所有变量都需要适应存储 NULL。所以它们都需要变体,因为这是唯一存储 NULL 的数据类型。
这很不幸,因为使用强类型变量会更好。
存储 Null 的变体与 Empty 的变体不同。 Null 表示为变量分配了一个值,并且该值为 Null。
这会让人感到困惑,因为数据库使用 Null 来表示字段中没有存储任何值,并且大多数数据库允许任何数据类型的字段为 Null。当一个数据库字段存储 Null 时,它相当于一个 VBA 变体变量,它刚刚被声明为一个值的“容器”,但还没有被赋予一个值。变量,就像表格字段一样,是一个没有任何东西的容器。
但是,如果从数据库表中为 VBA 变体变量提供了 Null 值,则它会存储它为 Null 的事实,因为这与从未被赋予值不同,并且是您的程序可能想要的信息区别对待。
另请注意,变量存储和空字符串“”不等于为空。
即“”不等于Empty(也不等于Null!)
当使用 MS Access 表存储文本时,我建议不要将“允许零长度”字段属性设置为 true,这是默认设置,因为这意味着您的数据库字段将能够存储“”(即空字符串)以及 Null 值。然后,您编写的任何代码都必须处理该字段将存储“”或 Null 的可能性。使用 Null 会更容易。
(很少需要在数据库表中存储空字符串)。
另一个有用的技术是使用MyString = Nz(MyStringDatabaseField) 将任何空值转换为空字符串。至少你的代码只需要测试空字符串而不是空值。这种技术还将简化使用存储空字符串的访问表的代码。有时使用 `MyInteger=Nz(MyIntegerDatabaseField) 将任何空值转换为 0 可能是合适的,但我对此感到非常不舒服,因为 0 比空字符串更有意义,而且真的是 Null 0!
请注意,在其表之间使用 OUTER JOIN 的 SQL 语句可能会导致返回的记录集在定义基础表字段以防止存储 NULL 的字段中包含 NULL 值。
请注意,如果您不使用数据类型的变体,则可能会意外使用默认值。例如
Dim aInt As Integer
aInt = Empty
Debug.Print aInt, " This will print 0, as 0 is the default value for integer variables"
下面的代码帮助我理解了可用于检查变体变量的各种函数之间的区别
Sub ExperimentsWithVariants()
Dim aInt As Integer
aInt = Empty
Debug.Print aInt, " This will print 0, as 0 is the default value for integer variables"
Dim avar As Variant ' The results shown as comments below were created when aVar was declared as a variant
Debug.Print "-----------------------"
Debug.Print "NOT SET:"
Debug.Print "-----------------------"
Debug.Print "TypeName(avar)", TypeName(avar) ' Empty
Debug.Print "aVar = Empty ", (avar = Empty) ' True
Debug.Print "aVar", avar ' '' ie blank
Debug.Print "IsNull(aVar)", (IsNull(avar)) ' False
Debug.Print "IsEmpty(aVar)", (IsEmpty(avar)) ' True
Debug.Print "aVar = """"", (avar = "") ' True
Debug.Print "aVar = 0", (avar = 0) ' True
If avar = Empty Then
Debug.Print " "
Debug.Print "avar = Empty so the above would be the same if you set avar = Empty explicitly"
Debug.Print " """
Else
avar = Empty
Debug.Print " "
Debug.Print "-----------------------"
Debug.Print " SET TO Empty"
Debug.Print "-----------------------"
Debug.Print "TypeName(avar)", TypeName(avar) ' Empty
Debug.Print "aVar = Empty ", (avar = Empty) ' True
Debug.Print "aVar", avar ' '' ie blank
Debug.Print "IsNull(aVar)", (IsNull(avar)) ' False
Debug.Print "IsEmpty(aVar)", (IsEmpty(avar)) ' True
Debug.Print "aVar = """"", (avar = "") ' True
Debug.Print "aVar = 0", (avar = 0) ' True
End If
avar = Null
Debug.Print " "
Debug.Print "-----------------------"
Debug.Print " SET TO NULL"
Debug.Print "-----------------------"
Debug.Print "TypeName(avar)", TypeName(avar) ' Null
Debug.Print "aVar = Empty ", (avar = Empty) ' Null
Debug.Print "aVar", avar ' Null
Debug.Print "IsNull(aVar)", (IsNull(avar)) ' True
Debug.Print "IsEmpty(aVar)", (IsEmpty(avar)) ' False
Debug.Print "aVar = """"", (avar = "") ' Null
Debug.Print "aVar = 0", (avar = 0) ' Null
avar = ""
Debug.Print " "
Debug.Print "-----------------------"
Debug.Print " SET TO EMPTY STRING ie """""
Debug.Print "-----------------------"
Debug.Print "TypeName(avar)", TypeName(avar) '
Debug.Print "aVar = Empty ", (avar = Empty) ' True
Debug.Print "aVar", avar ' '' ie blank
Debug.Print "IsNull(aVar)", (IsNull(avar)) ' False
Debug.Print "IsEmpty(aVar)", (IsEmpty(avar)) ' False
Debug.Print "aVar = """"", (avar = "") ' True
Debug.Print "aVar = 0", (avar = 0) ' String
' Note
' Is empty returns false, whereas ="" returns NULL
avar = 1.23
Debug.Print "-----------------------"
Debug.Print "SET to 1.23:"
Debug.Print "-----------------------"
Debug.Print "TypeName(avar)", TypeName(avar) ' Double
Debug.Print "aVar = Empty ", (avar = Empty) ' True
Debug.Print "aVar", avar ' '' ie blank
Debug.Print "IsNull(aVar)", (IsNull(avar)) ' False
Debug.Print "IsEmpty(aVar)", (IsEmpty(avar)) ' True
Debug.Print "aVar = """"", (avar = "") ' True
Debug.Print "aVar = 0", (avar = 0) ' True
' You can test for both an IsEmpty AND an empty string (ie "" ) AND a null value with:
' IIf(Len(avar & vbNullString)
Debug.Print "-----------------------"
Debug.Print "Using IIf(Len(avar & vbNullString) "
Debug.Print "-----------------------"
avar = ""
Debug.Print """""=", IIf(Len(avar & vbNullString) = 0, "Null, IsEmpty, or Empty String", "NOT")
avar = "1"
Debug.Print "1 = ", IIf(Len(avar & vbNullString) = 0, "Null IsEmpty,or Empty String", "NOT")
avar = Null
Debug.Print "Null = ", IIf(Len(avar & vbNullString) = 0, "Null, IsEmpty or Empty String", "NOT")
avar = Empty
Debug.Print "Empty = ", IIf(Len(avar & vbNullString) = 0, "Null or Empty String", "NOT")
Debug.Print "-----------------------"
Debug.Print "using TypeName"
Debug.Print "-----------------------"
Dim dbl1 As Double
Debug.Print "TypeName(dbl1) ", TypeName(dbl1) ' Double
Dim int1 As Integer
Debug.Print "TypeName(int1) ", TypeName(int1) ' Integer
Dim str1 As String
Debug.Print "TypeName(str1) ", TypeName(str1) ' String
End Sub
Sub ExperimentsWithNz()
Debug.Print " "
Debug.Print "---------------------------------------------------------------------- "
Debug.Print "---------------------------------------------------------------------- "
Debug.Print "1a Nz(Null)="""" =", Nz(Null) = ""
Debug.Print "1b IsNull(Nz(Null)) =", IsNull(Nz(Null)) ' False
Debug.Print "---------------------------------------------------------------------- "
Dim aVar As Variant
Debug.Print "2a Nz(aVar) Unassigned =", Nz(aVar) ' Null
aVar = Empty
Debug.Print "2b Nz(aVar) Empty =", Nz(aVar) ' Null
aVar = Null
Debug.Print "2c Nz(aVar) Null =", Nz(aVar) ' Null
Debug.Print "2d IsNull(Nz(aVar)) Null=", (IsNull(Nz(aVar))) ' Null
aVar = ""
Debug.Print "2e Nz(aVar) """" =", Nz(aVar) ' ' ie an empty string
Debug.Print "---------------------------------------------------------------------- "
Dim str1 As String
Debug.Print "3a Nz(str1) Unassigned =", Nz(str1) ' 0
str1 = Empty
Debug.Print "3b Nz(str1) Empty =", Nz(str1) ' 0
Debug.Print "---------------------------------------------------------------------- "
Dim int1 As Integer
Debug.Print "4a Nz(int1) Unassigned =", Nz(int1) ' 0
int1 = Empty
Debug.Print "5b Nz(int1) Empty =", Nz(int1) ' 0
' The following line cannot run as a string cannot be assigned Null
' str1 = Null
End Sub
Sub DealingWithEmptyStringsInADatabaseTable()
Dim aVar As Variant
Debug.Print "UNdeclared: ", Nz(aVar, 1)
aVar = Empty
Debug.Print "aVar=Empty ", Nz(aVar, 1)
aVar = Null
Debug.Print "aVar=Null ", Nz(aVar, 1)
aVar = ""
Debug.Print "aVar="""" ", Nz(aVar, 1)
Debug.Print " -------------------------------------------------------"
Debug.Print "Dealing with empty string in a database table"
aVar = ""
Debug.Print "IIf(aVar = "", 1, 0) ", IIf(aVar = "", 1, 0)
Debug.Print " "
Debug.Print " "
Debug.Print "-------------------------------------------------------"
Debug.Print "Dealing with a table field that can have Null or an Empty string"
Debug.Print "leads to more complex code than if is just stores NULL."
Debug.Print " "
Debug.Print "The code below shows WHY you should set the ""; Allow Zero Length "" property of access tables to false"
Debug.Print " "
aVar = Null
Debug.Print "1 Null : IIf(Nz(aVar & """" ,"""") = """", 1, 0) ", IIf(aVar & "" = "", 1, 0)
aVar = ""
Debug.Print "2 Empty String: IIf(Nz(aVar & """" ,"""") = """", 1, 0) ", IIf(aVar & "" = "", 1, 0)
Debug.Print " "
Debug.Print "Both lines 1 and 2 above work."
Debug.Print " "
Debug.Print " "
aVar = Null
Debug.Print "3 Null : Nz(aVar, 1) ", Nz(aVar, 1)
aVar = ""
Debug.Print "4 Empty String: Nz(aVar, 1) ", Nz(aVar, 1)
Debug.Print " "
Debug.Print "however, line 4 does not work for empty string."
Debug.Print "3 & 4 are much simpler than 1 & 2, but if your field can store """" and Null"
Debug.Print "you have to use 1 & 2. Which is a shame as 3 & 4 are simpler."
Debug.Print "Queries and code accessing this data can get messy"
End Sub