COMPANY SERVICE STAFF BLOG NEWS CONTACT
2026.10.16

MySQLのNULLの注意点

テクログ

お久しぶりです。
JGです。

今回はMySQL8系でのMySQLのNULLの注意点について、簡単に説明したいと思います。

演算にNULLが混ざると結果はすべてNULLになる

NULLを含む式では、その関数または演算子に関するドキュメントで明記されていないかぎり、常にNULL 値が生成されます。

https://dev.mysql.com/doc/refman/8.0/ja/functions.html

https://dev.mysql.com/doc/refman/8.0/ja/problems-with-null.html

  `created_at` datetime NOT NULL,
  `updated_at` datetime NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
INSERT INTO test1(name1, name2, sale1, sale2, created_at, updated_at) VALUES ('aa', 'bb', 10, 20, '2026-08-04 11:00:00', '2026-08-04 11:00:00');
INSERT INTO test1(name1, name2, sale1, sale2, created_at, updated_at) VALUES ('cc', NULL, 15, NULL, '2026-08-04 11:00:00', '2026-08-04 11:00:00');
INSERT INTO test1(name1, name2, sale1, sale2, created_at, updated_at) VALUES (NULL, 'dd', NULL, 25, '2026-08-04 11:00:00', '2026-08-04 11:00:00');
INSERT INTO test1(name1, name2, sale1, sale2, created_at, updated_at) VALUES (NULL, NULL, NULL, NULL, '2026-08-04 11:00:00', '2026-08-04 11:00:00');

上記のようなテーブルを作り、下記のSQLを実行すると先頭のsale_numは30になりますが、それ以外はNULLになります。

SELECT id, sale1 + sale2 AS sale_sum FROM test1;

NULLを0として扱いたい場合はIFNULL関数を使います。

SELECT id, IFNULL(sale1, 0) + IFNULL(sale2, 0) AS sale_sum FROM test1;

文字列の結合

文字列の結合も、下記のSQLを実行すると先頭のsale_numは「aa_bb」になりますが、それ以外はNULLになります。

SELECT id, CONCAT(name1, '_', name2) FROM test1;

NULLを空文字として扱いたい場合は先ほどのIFNULL関数を使います。

SELECT id, CONCAT(IFNULL(name1, ''), '_', IFNULL(name2, '')) FROM test1;

比較演算

https://dev.mysql.com/doc/refman/8.0/ja/working-with-null.html

比較演算子でnullを比較するとWHERE等でTRUEにはならないので、条件にはマッチしません。

下記の場合はsale1が10以上を取得し、NULLは取得できません。

SELECT id, sale1 FROM test1 WHERE sale1 >= 10;

下記の場合はsale1が10を取得し、NULLは取得できません。

SELECT id, sale1 FROM test1 WHERE sale1 = 10;

下記の場合はsale1が10以外を取得しますが、NULLは取得できません。

SELECT id, sale1 FROM test1 WHERE sale1 != 10;

NOT IN句での挙動

https://dev.mysql.com/doc/refman/8.0/ja//comparison-operators.html

NOT IN句にNULLがあると、sale1に15やNULLがあっても取得できず、何も取得できないため注意が必要です。

SELECT * FROM test1 WHERE sale1 NOT IN (15, NULL);

IN句での挙動

IN句にNULLがあると、sale1がNULLは取得できませんが、15は取得できます。

SELECT * FROM test1 WHERE sale1 IN (15, NULL);

COUNT(col)とCOUNT(*)の挙動

https://dev.mysql.com/doc/refman/8.0/ja/aggregate-functions.html#function_count

COUNT(col)はNULLを除外した数で、COUNT(*)はNULLを含む数です。

下記の場合はNULLを除外した数で、nameはNULLを許容しているため、2になります。

SELECT COUNT(name1) FROM test1;

下記の場合はNULLを除外した数ですが、idはNULLを許容していないため、4になります。

SELECT COUNT(id) FROM test1;

下記の場合はNULLを含む数のため、4になります。

SELECT COUNT(*) FROM test1;

ユニーク制約があってもNULLは重複して保存できる

CREATE TABLE `test2` (
  `id` int NOT NULL AUTO_INCREMENT,
  `name` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
  `created_at` datetime NOT NULL,
  `updated_at` datetime NOT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `unique_index_name` (`name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;

上記のようなテーブルを作り、下記のSQLを実行すると1個目はnameがユニークなので成功しますが、2個目は既に登録済みのnameなのでエラーになります。

INSERT INTO test2(name, created_at, updated_at) VALUES ('test', '2026-08-05 11:00:00', '2026-08-05 11:00:00');
INSERT INTO test2(name, created_at, updated_at) VALUES ('test', '2026-08-05 11:00:00', '2026-08-05 11:00:00');

下記のようにnameがNULLの場合は、2つも登録できます。

INSERT INTO test2(name, created_at, updated_at) VALUES (NULL, '2026-08-05 11:00:00', '2026-08-05 11:00:00');
INSERT INTO test2(name, created_at, updated_at) VALUES (NULL, '2026-08-05 11:00:00', '2026-08-05 11:00:00');

ORDER BY

ORDER BYでソートする場合、NULL値は、昇順ソートの場合は他の値の前にソートされ、降順ソートの場合は他の値の後にソートされます。

https://dev.mysql.com/doc/refman/8.0/ja/null-values.html

CREATE TABLE `test3` (
  `id` int NOT NULL AUTO_INCREMENT,
  `age` int NULL,
  `created_at` datetime NOT NULL,
  `updated_at` datetime NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
INSERT INTO test3(age, created_at, updated_at) VALUES (27, '2026-08-04 11:00:00', '2026-08-04 11:00:00');
INSERT INTO test3(age, created_at, updated_at) VALUES (36, '2026-08-04 11:00:00', '2026-08-04 11:00:00');
INSERT INTO test3(age, created_at, updated_at) VALUES (0, '2026-08-04 11:00:00', '2026-08-04 11:00:00');
INSERT INTO test3(age, created_at, updated_at) VALUES (NULL, '2026-08-04 11:00:00', '2026-08-04 11:00:00');
INSERT INTO test3(age, created_at, updated_at) VALUES (29, '2026-08-04 11:00:00', '2026-08-04 11:00:00');
INSERT INTO test3(age, created_at, updated_at) VALUES (33, '2026-08-04 11:00:00', '2026-08-04 11:00:00');

上記のようなテーブルを作り、下記のSQLを実行するとageがNULLのものが先頭になります。

SELECT * FROM test3 ORDER BY age ASC;

下記のSQLを実行するとageがNULLのものが末尾になります。

SELECT * FROM test3 ORDER BY age DESC;

昇順で並び替えをした場合に、NULLを末尾にしたい場合は下記にします。

age IS NULL ASCで、ageがNULLなら1、NULL以外なら0を返し、それを昇順で並び替えるとNULL以外を先に並び替えるからです。

SELECT * FROM test3 ORDER BY age IS NULL ASC, age ASC;

降順で並び替えをした場合に、NULLを先頭にしたい場合は下記にします。

SELECT * FROM test3 ORDER BY age IS NULL DESC, age DESC;

最後に

MySQLのNULLの注意点について、簡単に説明しました。

今回はこれで失礼します。

この記事を書いた人

JG

入社年
2020年
出身地
神奈川県
業務内容
プログラム
特技・趣味
サッカー観戦

テクログに関する記事一覧