HOME > 即効テクニック > Access VBA > コントロール > NullとEmptyとNothingと空の文字列の違い

NullとEmptyとNothingと空の文字列の違い|Access VBA

コントロール

NullとEmptyとNothingと空の文字列の違い

(Access 97/2000/2002/2003/2007/2010)

VBAでは変数やフィールドに有効な値がない状態や、空の状態を表す値がいくつもあります。
ここでは、それぞれの意味や使用上の注意についてご紹介します。

■長さ0の文字列("")

文字を1つも含まない文字列 ("") です。
「長さ0の文字列」の名前のとおり、Len関数やLenB関数の引数に指定すると0を返します。

    Dim myStr As String
    myStr = ""
    Debug.Print Len(myStr)     '--> 0 と表示される

■値0の文字列(vbNullString)

String型の変数の初期状態を表す値です。vbNullStringという定数で表します。
長さ0の文字列("")と同様に、Len/LenB関数の引数に指定すると 0 を返します。
また、「If vbNullString = "" Then」のように比較すると、True になります。
そのため、空の文字列として長さ0の文字列 ("")と区別されずに扱われることが多いですが、長さ0の文字列とは異なります。

値0の文字列と長さ0の文字列は、StrPtr関数で判別できます。
StrPtr関数はString型の変数のアドレス値を返す関数です。
StrPtr関数に 値0の文字列(vbNullString)を指定すると 0 を返します。
一方、長さ0の文字列("")を指定すると、変数のアドレス値を返します。
両者を区別する例については、「ユーザーの入力を文字列で取得する(InputBox関数)
の「空欄とキャンセルを識別する」の項目を参照してください。

■Empty

バリアント型の変数に格納される特殊な値(リテラル値)です。
Emptyは変数が初期化されていない状態を表します。バリアント型の変数の初期値です。
また、Emptyを格納できるのはバリアント型だけです。

ここで少しバリアント型について見てみましょう。
バリアント型は、文字列や数値、日付やブール値など、いろいろなデータを扱うことができる特殊なデータ型です。Emptyのほか、Nullなどの特殊な値もバリアント型のリテラル値です。
バリアント型には、「データの値」を表す部分と、「そのデータがどのような型で入っているか」を表す部分があります。後者を内部処理形式といい、VarType関数やTypeName関数で調べることができます。

Emptyは特殊な内部処理形式を持ち、VarType関数の引数に指定するとvbEmptyを返します。
また、Emptyかどうかは、次のようにIsEmpty関数で判定します。

    Dim myVar As Variant
    Debug.Print VarType(myVar)   '--> 0(定数vbEmpty)と表示される
    Debug.Print TypeName(myVar)  '--> Empty と表示される
    Debug.Print IsEmpty(myVar)   '--> True と表示される

VBAでは、明示的に型を変換しなくても、暗黙的に型の変換(型強制)が行われます。
バリアント型のEmptyを文字列として扱うと、String型に型強制されて長さ0の文字列("")になり、数値として扱うと0に、ブール値として扱うとFalseになります。

    Dim myVar As Variant                    '初期値はEmpty
    If myVar = 0 Then Debug.Print "True"    '--> True と表示される
    If myVar = "" Then Debug.Print "True"   '--> True と表示される

ちなみに、Excelのセルを表すRangeオブジェクトのValueプロパティはバリアント型で、初期値はEmptyです。セルが初期状態のとき、長さ0の文字列や数値の0と比較するとTrueになるのは、Emptyがこれらに型強制されているためです。あわせて覚えておくと良いでしょう。

■Null

Nullは、バリアント型の変数に格納される特殊な値(リテラル値)です。
特殊な内部処理形式(vbNull)を持ち、有効なデータが格納されていないことを表します。
NullかどうかはIsNull関数で判定します。

    Dim myVar As Variant        '初期値はEmpty
    myVar = Null                'Nullを代入
    Debug.Print VarType(myVar)  '--> 1(定数vbNull)と表示される
    Debug.Print TypeName(myVar) '--> Null と表示される
    Debug.Print IsNull(myVar)   '--> True と表示される

Nullを格納できるのはバリアント型だけです。
ADOやDAOを使ってデータベースを扱う場合、フィールドを操作するオブジェクトのValueプロパティはバリアント型のため、値のない状態として Null を扱うことができます。

また、変数やフィールド、Accessフォーム/レポートのコントロールがNullになるのは、次のケースです。

  1. 1) 明示的にNullを代入したとき
  2. 2) Nullを含む演算(計算)を行ったとき
  3. 3) フィールドやAccessフォーム/レポートコントロールに有効な値がないとき

このうち、2)については、値がないものと演算をするのですから、結果も有効な値にならないというわけです。当然ですね。
3)については、少し注意が必要です。というのも、フィールドを表すオブジェクトやコントロールのValueプロパティはバリアント型です。そしてバリアント型の初期値は前述のとおりEmptyです。しかし、フィールドに有効な値がない場合や、バインドしていない(非連結)コントロールの場合、初期値はEmptyでなくNullになっています。

    Dim Rst As DAO.Recordset
    Dim myStr As String, myLong As Long
    
    Set Rst = CurrentDb.OpenRecordset("Select * From テーブル1")
    Rst.MoveFirst
    
    With Rst.Fields
        Debug.Print TypeName(.Item("TextField").Value)
        Debug.Print TypeName(.Item("LongField").Value)

        myStr = .Item("TextField").Value    '--(※)
        myNum = .Item("LongField").Value    '--(※)    
    End With
    Rst.Close

テーブル1の[TextField]フィールド、[LongField]フィールドにそれぞれ文字列と数値が入っているとき、レコードセットのフィールドは内部処理形式String型、Long型となりますが、テーブル1の両フィールドに値がないとき、どちらもNullとなります。
NullのときにString型やLong型の変数に代入すると、Emptyのように型変換されないため、(※)のコードでエラーとなります。

    Dim myVar As Variant         '初期値はEmpty
    myVar = Me!テキスト0.Value   '未入力の状態でValueを代入
    Debug.Print TypeName(myVar)  '--> Null と表示される

また、非連結のコントロールのValueプロパティもバリアント型ですが、初期値はEmptyでなくNullになっています。そのため、この例では「Null」と表示されます。

●補足1●

Excelのユーザーフォームにもテキストボックスがありますが、Acccessのフォーム/レポートのテキストボックスとは異なります。
Excelのユーザーフォームで使用するテキストボックスの場合、Valueプロパティはバリアント型ですが、内部処理形式はString型で、値0の文字列(vbNullString)に初期化されています。

●補足2●

レコードセットを使用して処理を行う場合、元のフィールドが数値型でも値がなければNullになるため、それを使って演算すると結果はNullになってしまいます。
値がないときには別の値に置き換えたいという場合は、演算前にNullかどうかを判定するか、またはNz関数を使用して別の値に置き換えてもよいでしょう。
ただし、「If myVar = Null」や「If myVar <> Null」のように比較するといずれもFalseになってしまうので、Nullの判定にはIsNull関数を使用してください。

■Nothing

オブジェクト変数に格納される特殊な値(リテラル値)です。
オブジェクト変数が特定のオブジェクトと関係付けられていないことを表します。
オブジェクト変数を宣言した後、オブジェクトへの参照が設定されるまで、オブジェクト変数にはNothingが設定されています。
また、オブジェクト変数が特定のオブジェクトを参照しているとき、Setステートメントを使用して次のように記述すると、オブジェクト変数と参照先のオブジェクトとの関係が無効になります。

    Set myObj = Nothing

ただし、オブジェクト変数にNothingを代入しても、オブジェクトを破棄しているわけではないことに注意してください。
オブジェクトは、どこからも参照されなくなったときに、自分自身を破棄する仕組みになっています。そのため、複数のオブジェクト変数が同じオブジェクトを参照している場合は、すべての変数に明示的にキーワードNothingを設定するか、または参照しているすべてのオブジェクト変数の適用範囲 (スコープ) 外になるまで、リソースは解放されません。
Nothingについては「『Set a = Nothing』のお話」を参照してください。

オブジェクト変数がNothingであるかどうかを確認するには、Is演算子を使用します。

    If myObj Is Nothing Then
        Set myObj = Forms![フォーム1]
    End If

この例では、オブジェクト変数Objが特定のオブジェクトと関連付けられていない場合は、Objにフォーム1を割り当てています。

【最後に】

このように、VBAには値のない状態や空であることを表す値が何種類もあります。
VBAでは暗黙的に型変換が行われるため、気付かずに使ってしまいがちですが、空の文字列には2種類あること、EmptyとNullはバリアント型に格納される値であること、それぞれがどのような状態を表す値であるのかを確認しておきましょう。
特に、データベース操作ではNullを扱う機会が多いので、データベースに格納されている値と、変数やレコードセット、コントロールの初期値がどうなっているかを意識してプログラミングするようにしましょう。