Типы данных, допускающие значение 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, позволяющая распаковать содержимое опционального типа.

Предыдущая
Следующая