четверг, 25 мая 2023 г.

Неизвестное vs Отсутствующее, или Двуликий NULL

Когда-то я уже писал о "многоликом NULL", см. Часть I и Часть II. Сегодняшний пост в дополнение и в развитие этой темы.

Я неоднократно встречал утверждение, что NULL в SQL нужно понимать как "неизвестно что". С этим согласуется поведение операторов сравнения при сравнении двух NULL (команды выполнены в PostgreSQL 15):

select 1
where null = null
   or null != null
   or null < null
   or null <= null
   or null >= null
   or null > null
;

no rows

Не выбрано ничего, так как по умолчанию принимается, что два неизвестных значения не равны.

Однако, на практике NULL используется в таблицах БД не только для обозначения неизвестного значения, но и для обозначения отсутствующего значения. А это "две большие разницы". И одно отсутствующее значение должно быть равно другому отсутствующему значению того же типа, как равны две пустые строки (команды выполнены в PostgreSQL 15):

select 1 where '' = '';

1

select 2 where '' != '';

no rows

Я взял пустые строки, чтобы проиллюстрировать, как должны работать отсутствующие значения любого типа. К сожалению, в SQL нет пустых чисел, пустых дат и пустых булевых значений, которые могли бы сойти за отсутствующие.

В чем разница между неизвестным и отсутствующи значением? В том, что неизвестное неизвестно, а отсутствующее не существует.

Так незаполненный пункт анкеты "Дети" говорит об отсутствии детей, а не о том, что о детях ничего неизвестно.

Пусть у нас есть таблица товаров, в которой одно из полей содержит дату первой продажи товара в магазине. Отсуствие даты первой продажи говорит о том, что продажи еще не было, а не о том, что дата состоявшйеся первой продажи неизвестна. Дата первой продажи пуста, но не неизвестна; она отсутствует, поскольку не было факта продажи, и ее отсуствие – это отражение отсутствия факта.

Не логично ли было бы иметь пустые (с семантикой отсутствия) значения для всех типов SQL в дополнение к неизвестным значениям NULL? Тогда в нашей таблице товаров столбец с датой первой продажи имел бы ограничение NOT NULL и пустое значение (NONE? EMPTY?) по умолчанию.

На практике я не раз встречал использование в качестве отсутствующего значения определенных значений, выбранных разработчиком. Например, в таком качестве часто используются -1 и '-1', когда эти значения не могут быть истолкованы двояко (то есть, когда они не являются допустимыми "нормальными" значениями в соответствующих столбцах).

Интересное новшество, касающееся уникальности NULL, предложено в стандарте SQL:2023, см. статью SQL:2023 is finished: Here is what's new. При построении уникального индекса станет возможным указать, нужно ли трактовать разные NULL как уникальные значения (то есть, неизвестные, по умолчанию не равные друг другу), либо как одинаковые (в сущности, отсутствующие и равные друг другу).

Комментариев нет:

Отправить комментарий