みーのぺーじ

みーが趣味でやっているPCやソフトウェアについて.Python, Javascript, Processing, Unityなど.

SQL で NULL との比較が unknown になる

SQL では,NULLに比較述語を適用すると,常にunknownになります.これは分かりにくい印象がありますが,3値論理に準拠すれば明らかです.

この性質により,例えば Django で以下のように apple_iduniquenull が共存できます.ここで,apple_id は必須ではないけれども他のりんごとは重複しない数値のことです.

from django.db import models

class Apple(models.Model):
    apple_id = models.IntegerField(unique=True, null=True)

なお,以下の環境で動作確認をしました.

PostgreSQL 15.1 (Debian 15.1-1.pgdg110+1) on x86_64-pc-linux-gnu
Django==4.1.3
psycopg2==2.9.5

これの unittest は以下のようになり,実行すると成功します.

from django.db.utils import IntegrityError
from django.test import TransactionTestCase

from .models import Apple

class AppleTest(TransactionTestCase):
    def test_unique_field(self):
        with self.assertRaises(IntegrityError):
            Apple.objects.create(apple_id=1)
            Apple.objects.create(apple_id=1)
        self.assertEqual(Apple.objects.count(), 1)

    def test_unique_and_null_field(self):
        Apple.objects.create(apple_id=None)
        Apple.objects.create(apple_id=None)
        self.assertEqual(Apple.objects.count(), 2)
Found 2 test(s).
Creating test database for alias 'default'...
System check identified no issues (0 silenced).
..
----------------------------------------------------------------------
Ran 2 tests in 0.165s

OK

apple_id が NULL な Apple が複数存在しても,NULL = NULL は unknown なので,unique に違反しないためです.