TL;DR — Null は 「ひとつの答えがない」 ことを表すタグです。Excel VBA では、Null をセルから受け取ることはまずありません。空のセルは Empty なので、空白のセルに対する
IsNullは常に False です。Null が返ってくるのは、セルごとに値が食い違う範囲 のプロパティを読んだとき、たとえば太字と標準のセルが混じった範囲のFont.Bold、表示形式が混在した範囲のNumberFormat、高さの違う行にまたがるRowHeightなどと、データベースのフィールドを読んだときです。ここから二つのルールが導かれます。判定にはIsNullだけを使うこと(x = Nullはそれ自体が Null になり、決して True にならないため)。そして範囲全体のプロパティはVariantに読み込むこと(Boolean、String、Doubleに Null を代入すると エラー 94 Invalid use of Null、日本語版 Excel では「Null の使い方が不正です。」で止まるため)。
Dim bold As Variant
bold = Range("A1:A10").Font.Bold
If IsNull(bold) Then Debug.Print "Some cells are bold, some are not"
この記事は、値に「あなたは何者か」を尋ねる シリーズの第三回です。一度も代入されていない値には IsEmpty、どんなタグでも読み取るには VarType と TypeName、そして今回は混在または不明を意味するタグを判定する IsNull を扱います。シリーズを貫く考え方は、VBA の値は中身とは別に型のタグを持っていて、これらの判定は見た目ではなくタグを読んでいる ということです。
この記事で学べること
- 考え方の軸:Null は「ひとつの答えがない」という意味
- Excel で Null が来る場所と、来ない場所
- = Null が決して動かない理由
- エラー 94「Null の使い方が不正です。」
- Null が式の中を伝わっていく仕組み
- 混在した範囲を三つ目の答えとして扱う
- データベースから来る Null は境界で処理する
考え方の軸:Null は「ひとつの答えがない」という意味
Empty は 一度も値が入れられていない という意味です。Null は 入れるべきひとつの値が存在しない という意味です。「この範囲は太字か?」という問いには、正直な答えが三つあります。はい、いいえ、そして「一部だけ」です。VBA には三つ目の Boolean がないので、Null を保持した Variant で答えるのです。
Null を「セル同士の意見が食い違っている」あるいは「値が不明」と捉えれば、その振る舞いは納得がいきます。不明な値との比較の結果は不明です。不明な値を含む合計も不明です。そして True か False しか保持できない Boolean 型の変数には、「一部だけ」を入れる場所がありません。
Excel で Null が来る場所と、来ない場所
セルからは来ません。 空のセルの値は Empty、"" が入ったセルは String、エラーのセルは Error です。IsNull(Range("A1").Value) はこれらすべてで False になります。だから空白セルの判定に IsNull を使っても決して反応しないのです。その用途には IsEmpty を使ってください。
値が食い違うセルにまたがる範囲のプロパティから来ます。 多くの Range のプロパティは、範囲内のセルがひとつの値を共有していないときに Null を返します。
| 複数セルの範囲に対するプロパティ | Null を返す条件 |
|---|---|
Font.Bold、Font.Italic |
太字や斜体のセルとそうでないセルが混在している |
Font.Name、Font.Size、Font.Color |
セルごとにフォント、サイズ、色が違う |
NumberFormat |
セルごとに表示形式が違う |
HorizontalAlignment、WrapText |
セルごとに配置や折り返しの設定が違う |
RowHeight、ColumnWidth |
行の高さや列の幅が違う |
HasFormula |
数式のセルと定数のセルが混在している |
MergeCells、Locked |
結合やロックされたセルとそうでないセルが混在している |
一部だけが太字になった選択範囲の Selection.Font.Bold が日常的な例です。それを表す True も False もないので、答えは Null になります。
Excel の外から来ます。 ADO でデータベースから読み取ったフィールドは、データベースの列が NULL を保持していれば Null になります。
= Null が決して動かない理由
最初に思いつくのは比較です。
v = Range("A1:A10").Font.Bold
If v = Null Then Debug.Print "mixed" ' 決して出力されない
If v <> Null Then Debug.Print "not mixed" ' こちらも決して出力されない
Null との比較は、それ自体が Null になります。不明なものと比較すれば、結果も不明だからです。If は Null の条件を True ではないものとして扱うので、v に何が入っていても、上の 両方 の分岐が飛ばされます。コンパイルエラーも実行時エラーも出ません。チェックが黙って死んでいるのです。正しく動く判定は IsNull(v) だけです。
エラー 94「Null の使い方が不正です。」
次に思いつくのは、期待する型で宣言することです。
Dim isBold As Boolean
isBold = Range("A1:A10").Font.Bold ' Run-time error 94: Invalid use of Null
このコードは、範囲がすべて太字かすべて標準になっているテスト用のシートでは必ず動き、ユーザーがセルをひとつだけ太字にした最初の日に失敗します。表示形式が混在した範囲での Dim fmt As String: fmt = rng.NumberFormat、高さの違う行での Dim h As Double: h = Rows("1:5").RowHeight、そして CStr(Null) や CLng(Null) でも同じことが起きます。Null を保持できるのは Variant だけです。
直し方はいつも同じです。範囲全体のプロパティは Variant に読み込み、IsNull で判定してから変換する。
Dim fmt As Variant
fmt = rng.NumberFormat
If IsNull(fmt) Then
Debug.Print "Mixed formats in " & rng.Address
Else
Debug.Print "All cells use " & fmt
End If
Null が式の中を伝わっていく仕組み
Null は算術演算やほとんどの関数を通じて伝わっていきますが、& 演算子では伝わりません。
Dim n As Variant
n = Null
Debug.Print n + 1 ' Null
Debug.Print Len(n) ' Null
Debug.Print "Total: " + n ' Null (+ は Null を伝える)
Debug.Print "Total: " & n ' Total: (& は Null を "" として扱う)
つまり計算に入り込んだ Null は最後まで運ばれていき、型付きの変数や実際の値を必要とする関数にたどり着いた時点で初めて失敗します。目にするエラー 94 は、Null が入り込んだ場所から何行も後ろかもしれません。エラー 94 に出会ったら、失敗した行ではなく、その式の中で最初に読み取ったプロパティやフィールドを探してください。
混在した範囲を三つ目の答えとして扱う
混在はエラーではなく情報です。マクロがそれをどう扱うべきかを決めてください。よく使われるルール、つまり Word の太字ボタンが採用しているルールは、混在した選択範囲をすべて太字にするというものです。Not だけで書いた切り替えでは、この選択ができません。Not Null は Null だからです。
Sub ToggleBold()
Dim rng As Range, state As Variant
If TypeName(Selection) <> "Range" Then Exit Sub
Set rng = Selection
state = rng.Font.Bold
If IsNull(state) Then
rng.Font.Bold = True ' 混在:すべて太字にする
Else
rng.Font.Bold = Not state
End If
End Sub
上の表にあるどのプロパティにも同じパターンが使えます。Variant に読み込み、混在のケースに専用の分岐を与えてから処理します。列の幅や行の高さなら、混在の分岐はたいてい「すべてをひとつの値にそろえる」です。NumberFormat なら、何かを上書きする前に「どのセルが違うのかを報告する」のが普通です。
データベースから来る Null は境界で処理する
ADO でレコードを読むと、NULL の列はすべて Null として届き、型付きの変数に入れたり合計に加えたりした瞬間に失敗します。コードに入ってくる場所で一度だけ変換してください。Excel VBA には Nz 関数がない(あれは Access の関数です)ので、小さな関数を自分で書きます。
Function NzV(ByVal v As Variant, Optional ByVal ifNull As Variant = "") As Variant
If IsNull(v) Then NzV = ifNull Else NzV = v
End Function
total = total + NzV(rs!Amount, 0)
customer = NzV(rs!CustomerName, "")
Range.CopyFromRecordset でレコードセット全体をシートに書き出す場合は、変換は不要です。Null のフィールドは空のセルになります。
判断の分かれ目:Null はバグではなく三つ目の答え
Null にまつわる不具合のほとんどは、「一部だけ」を入れる余地を残さなかった型宣言です。それを防ぐルールはこうです。複数セルの範囲から読み取ったプロパティは必ず Variant に入れ、混在のケースには専用の分岐を与える。 = Null で比較してはいけません。範囲全体のプロパティを Boolean、String、Double に直接流し込んでもいけません。
そして、セルの判定に IsNull を持ち出さないでください。空白のセルは Empty、クリアした入力は ""、失敗した検索は Error です。コードが IsNull でセルを判定しているなら、本当に必要なのは IsEmpty、Len、IsError のどれかです。
ExcelMaster の活用
書式を読み取るコードは、たいてい実際のブックで壊れます。範囲が完全に均一であることはまずないからです。太字のセルがひとつ、結合された見出しがひとつ、ほかより少しだけ高い行がひとつ、といった具合です。
ExcelMaster はコードを書く前に実際の範囲の書式を調べ、セル同士が食い違う場所を見つけて、混在のケースをエラー 94 に任せず明示的に処理します。
よくある質問
VBA の IsNull は何をする関数ですか?
IsNull(v) は、v が Null を保持する Variant であれば True を返します。Null は「ひとつの答えがない」または「不明」を意味する値です。Excel では主に、値が食い違うセルにまたがる範囲のプロパティと、データベースのフィールドから出会います。
空のセルなのに IsNull が False を返すのはなぜですか?
空のセルは Null ではなく Empty だからです。一度も入力されていないセルを判定するには IsEmpty(Range("A1").Value) を使ってください。
実行時エラー 94「Null の使い方が不正です。」(Invalid use of Null)の原因は何ですか?
Boolean、String、Long、Double のように Null を保持できない変数に Null を代入したり、CStr などの関数に Null を渡したりしたことが原因です。値を Variant に読み込み、先に IsNull で判定してください。
VBA で If x = Null が決して動かないのはなぜですか?
Null との比較はすべて Null を返し、If は Null を True ではないものとして扱うからです。x = Null も x <> Null も飛ばされます。IsNull(x) を使ってください。
VBA で範囲の書式が混在しているかどうかを調べるには?
プロパティを Variant に読み込んで判定します:If IsNull(rng.Font.Bold) Then。Font.Bold、NumberFormat、RowHeight、HorizontalAlignment などのプロパティは、セルごとに値が違うと Null を返します。
検証環境
検証環境: Excel 365 (Windows 11)、VBA 7.1 — 最終確認 2026-10-04。
関連ガイド: VBA IsEmpty · VBA VarType and TypeName · VBA Nothing · VBA Font · VBA Number Format · VBA Column Width · VBA Data Types · VBA Error Handling
