Типы данных, допускающие значение NULL
Любые типизированные данные в YQL, включая столбцы таблиц, бывают как гарантированно имеющие значение, так и потенциально пустые (что обозначается как NULL
). Типы данных, которые могут содержать значения NULL
, называются опциональными или, в терминах SQL, — nullable.
Опциональные типы данных в текстовом виде обозначаются вопросительным знаком в конце (например, String?
) или как Optional<...>
.
Наиболее часто на опциональных типах данных выполняются следующие операции:
- IS NULL - проверка на пустое значение
- COALESCE - оставить заполненные значения без изменений, а
NULL
заменить на указанное следом значение по умолчанию - UNWRAP - извлечь значение оригинального типа из опционального,
T?
преобразуется вT
- JUST — добавить опциональность к текущему типу,
T
преобразуется вT?
- NOTHING — создать пустое значение с указанным типом.
Optional
(nullable) является не свойством типа данных или колонки, а одним из видов контейнеров, которые могут быть произвольным образом вложены друг в друга. Так, например, столбец с типом Optional<Optional<Boolean>>
может принимать 4 значения - NULL
всего контейнера, NULL
внутреннего контейнера, TRUE
и FALSE
. Описанный тип отличается от List<List<Boolean>>
тем, что роль пустого списка в нем играет NULL
и отсутствует возможность положить больше одного содержательного элемента. Также значения типа Optional<Optional<T>>
возвращаются в качестве результата поиска по ключу в словаре Dict(k,v)
со значениями типа Optional<T>
. Такой тип данных результата позволяет отличать лежащий в словаре NULL
от ситуации отсутствия ключа.
Примечание
По умолчанию, при указании примитивного типа T
как типа колонки таблицы YDB в базе данных создается соответсвующий контейнерный тип Optional<T>
. Колонку с типом T
можно создать, используя ключевое слово NOT NULL
.
В явном виде контейнерные типы (включая контейнеры Optional<T>
и производные от них более сложные типы) в настоящее время нельзя использовать в качестве типов данных колонок при создании таблиц YDB.
Запросы YQL могут возвращать значения контейнерных типов, а также принимать их в качестве входных параметров.
Пример
$dict = {"a":1, "b":null};
$found = $dict["b"];
select if($found is not null, unwrap($found), -1);
Результат:
# column0
null
Логические и арифметические операции с NULL
Литерал NULL
имеет отдельный сингулярный тип Null
и может быть неявно сконвертирован к любому опциональному типу (в том числе и вложенному Optional<Optional<...Optional<T>...>>
). В ANSI SQL NULL
имеет семантику "неизвестное значение" – поэтому логические и арифметические операции с NULL
или с незаполненными Optional
имеют некоторые особенности.
Примеры
SELECT
True OR NULL, -- Just(True) (работает как True OR <неизвестное значение типа Bool>)
False AND NULL, -- Just(False)
True AND NULL, -- NULL (точнее Nothing<Bool?> – <неизвестное значение типа Bool>)
NULL OR NOT NULL, -- NULL (все NULL-ы "разные")
1 + NULL, -- NULL (Nothing<Int32?>) - результат сложения 1 с
-- неизвестным значением типа Int)
1 == NULL, -- NULL (результат сравнения 1 с неизвестным значением типа Int)
(1, NULL) == (1, 2), -- NULL (сравнение композитных элементов производится покомпонентно
-- через `AND`)
(2, NULL) == (1, 3), -- Just(False) (выражение эквивалентно 2 == 1 AND NULL == 3)
Типы данных, не допускающие значение NULL
Примитивные типы YQL не могут хранить в себе значение NULL
: для хранения NULL
предназначен описанный выше контейнер Optional
. В терминах SQL примитивные типы YQL являются non-nullable типами.
В YQL отсутствует неявное преобразование типов из Optional<T>
в T
, поэтому выполнимость NOT NULL
ограничения на колонку таблицы обеспечивается на этапе компиляции запроса YDB.
Создать non-nullable колонку в таблице YDB можно с помощью операции CREATE TABLE, пользуясь ключевым словом NOT NULL
.
Пример
CREATE TABLE t (
Key Uint64 NOT NULL,
Value String NOT NULL,
PRIMARY KEY (Key))
После этого операции записи в таблицу t
будут выполняться, только если среди значений на вставку в колонки key
, value
будут отсутствовать значения NULL.
Пример взаимодействия NOT NULL ограничения с функциями YQL
Многие из функций YQL имеют опциональные типы в качестве возвращаемого значения. Так как YQL является строго типизированным языком, запрос вида
CREATE TABLE t (
c Utf8 NOT NULL,
PRIMARY KEY (c)
);
INSERT INTO t(c)
SELECT CAST('q' AS Utf8);
не может быть исполнен. Причиной этому является несоответствие типов колонки c
, имеющей тип Utf8
, и результата функции CAST
, имеющей тип Optional<Utf8>
. Для корректной работы запроса в таких сценариях требуется использовать функцию COALESCE, аргументом которой можно указать fallback-значение для вставки в таблицу для случая, когда функция (в примере CAST
) вернет пустой Optional
. Если же в случае пустого Optional
нужно не выполнять вставку, а вернуть ошибку, то для этого подойдет функция UNWRAP, позволяющая распаковать содержимое опционального типа.