本記事では、SQL Serverにおける「NULL制約」について、初心者向けにわかりやすく解説します。
NULLとは何か、どのように制約を付与・変更するのか、データ設計上の注意点は何かを順を追って学び、最後に演習問題で理解度をチェックしましょう。
この記事を通して、SQL Serverでのテーブル設計に自信を持てるようになることを目標としています。
NULLとは何か?
NULLは「値が存在しないこと」を示す特殊な状態です。文字列でいう空文字や数値の0とは異なり、未定義・不明を表します。
空文字は「長さ0の文字列」であり、NULLは「そもそも値がない」状態です。比較結果も異なり、空文字は ‘=’’’ で真と判定できますが、NULLは IS NULL で判定します。
顧客の第2連絡先が未登録、アンケートの任意回答、退職日が未定など、値がまだ定まっていない・そもそも存在しないデータを扱う際に利用します。
NULL制約(NULL / NOT NULL)の基本
SQL Serverではテーブル作成時に各カラムに対し、以下のようにNULL制約を設定します。
CREATE TABLE Employees (
EmployeeID INT NOT NULL, -- NULLを許可しない
LastName NVARCHAR(50) NOT NULL,
FirstName NVARCHAR(50) NOT NULL,
BirthDate DATE NULL, -- NULLを許可
HireDate DATE NOT NULL
);
- NOT NULL :必ず値を入力しなければならない
- NULL :値を省略できる(デフォルトはNULL許可)
テーブル作成時、何も指定しなければ暗黙的に NULL が設定されます。また、プライマリキー(PRIMARY KEY)は自動的に NOT NULL となります。
既存テーブルへのNULL制約追加・変更
既に作成したテーブルに対して、ALTER TABLE 文でNULL制約を追加・変更する方法を説明します。
NULL→NOT NULLに変更する
-- まずはNULLを含まないように既存データを更新する
UPDATE Employees
SET BirthDate = '1900-01-01'
WHERE BirthDate IS NULL;
-- 制約を変更
ALTER TABLE Employees
ALTER COLUMN BirthDate DATE NOT NULL;
NOT NULL→NULLに変更する
ALTER TABLE Employees
ALTER COLUMN MiddleName NVARCHAR(50) NULL;
変更の際、NULLを許可しない方向(NOT NULL)へ切り替える場合は、既存データにNULLが含まれていないことを必ず確認・補正してください。
NULL制約を伴う制約(DEFAULT・CHECK)の活用
INSERT時に値が指定されなかった場合、自動でデフォルト値を設定します。NULLを許可しないカラムにデフォルトを設定しておくと便利です。
CREATE TABLE Orders (
OrderID INT NOT NULL IDENTITY(1,1) PRIMARY KEY,
OrderDate DATETIME NOT NULL DEFAULT(GETDATE()),
ShipAddress NVARCHAR(200) NULL
);
複合条件でNULLを扱いつつ制約をかけたい場合に用います。
CREATE TABLE Products (
ProductID INT NOT NULL PRIMARY KEY,
Price DECIMAL(10,2) NOT NULL CHECK(Price >= 0),
Discount DECIMAL(5,2) NULL CHECK(Discount BETWEEN 0 AND 100)
);
NULL制約に関する注意点
- パフォーマンスへの影響
NULLを許可するとインデックスを貼る際に余分な領域を使う場合があります。頻繁に検索するカラムは可能なら NOT NULL に設計するのが無難です。 - 論理演算の違い
三値論理(TRUE, FALSE, UNKNOWN)により、WHERE Col = 100 OR Col <> 100 でもNULLは弾かれます。NULL状態は UNKNOWN となるため、必ず IS NULL を併用してください。 - 集計関数での取り扱い
COUNT(*) はNULLを含めますが、COUNT(Column) はNULLを除外します。期待した結果が得られないケースがあるので注意が必要です。
まとめ
- NULLは「値がないこと」を示す特殊値で、空文字や0と異なる扱いをします。
- テーブル作成時にカラム単位でNULL/NOT NULLを指定でき、既存カラムもALTER TABLEで変更可能です。
- デフォルト値(DEFAULT)やチェック制約(CHECK)と組み合わせると、より堅牢なデータ設計が実現します。
- 検索・演算時の三値論理やインデックスへの影響に注意し、適切に設計しましょう。
演習問題
問題1:テーブル作成問題
Customers テーブルを作成してください。
- CustomerID:INT、主キー、自動採番。
- Name:NVARCHAR(100)、必須。
- Email:NVARCHAR(200)、任意。
- RegistrationDate:DATETIME、必須、デフォルトは現在日時。
問題2:NULL→NOT NULL変更問題
既存の Products テーブルの Description カラム(現在は NULL 許可)を NOT NULL に変更し、NULLレコードはすべて空文字に置き換えてください。
問題3:論理演算問題
Orders テーブルにおいて、ShipDate がNULLまたは2025年1月1日以降のレコードを抽出するSQLを書いてください。
問題4:集計関数の違い
Sales テーブルの Amount カラムにNULLが含まれています。
全レコード数と、NULLを除いたレコード数をそれぞれ取得するSQLを2つ書いてください。
問題5:CHECK制約追加問題
Employees テーブルの Age カラムに対し、18~65歳の範囲であることを保証するCHECK制約を追加してください。
解答例
解答例1. テーブル作成問題
CREATE TABLE Customers (
CustomerID INT NOT NULL IDENTITY(1,1) PRIMARY KEY,
Name NVARCHAR(100) NOT NULL,
Email NVARCHAR(200) NULL,
RegistrationDate DATETIME NOT NULL CONSTRAINT DF_Customers_RegDate DEFAULT(GETDATE())
);
解答例2. NULL→NOT NULL変更問題
-- NULLを空文字に置換
UPDATE Products
SET Description = ''
WHERE Description IS NULL;
-- 制約をNOT NULLに変更
ALTER TABLE Products
ALTER COLUMN Description NVARCHAR(500) NOT NULL;
解答例3. 論理演算問題
SELECT *
FROM Orders
WHERE ShipDate IS NULL OR ShipDate >= '2025-01-01';
解答例4. 集計関数の違い
-- 全レコード数(NULL含む)
SELECT COUNT(*) AS TotalCount
FROM Sales;
-- NULLを除いたレコード数
SELECT COUNT(Amount) AS NonNullCount
FROM Sales;
解答例5. CHECK制約追加問題
ALTER TABLE Employees
ADD CONSTRAINT CK_Employees_Age CHECK (Age BETWEEN 18 AND 65);
以上で、SQL ServerのNULL制約に関する基礎的な説明と演習問題を終わります。実際に手を動かしながら試してみてください。データ設計の理解がより深まるはずです!