В процессе преобразования примитивных типов данных часть исходной информации может быть отброшена, если она не содержится в целевом типе. Например:
Дробная часть Float/Double при преобразовании в целочисленные типы;
Время Datetime/Timestamp при преобразовании в Date.
Таймзона при преобразовании из типов с таймзоной к типу даты/времени без таймзоны.
Если для определённого сочетания исходного и целевого типа преобразование не может быть выполнено для всех возможных значений исходного типа, то при неудачном преобразовании CAST вернёт NULL. В таких случаях к типу возвращаемого значения добавляется один уровень Optional, если его не было. Например, конструкции: CAST("3.14" AS Float?) и CAST("3.14" AS Float) полностью эквиваленты и возвращают Float?.
Если же преобразование возможно для всех значений исходного типа, то добавление '?' работает как Just сверху: CAST(3.14 AS Utf8?) то же, что и Just(CAST(3.14 AS Utf8))
Все сочетания примитивных типов, для которых возможен CAST описаны тут.
Правила преобразований для контейнеров.
Правила для Optional
Если для целевого типа задан больший уровень Optional чем для исходного то это эквивалентно добавлению Just поверх CAST с меньшим уровнем Optional.
Если же больший уровень Optional у исходного типа, то NULL на любом уровне больше целевого приводит к NULL в результате.
При равных уровнях Optional значение NULL остаётся на том же уровне.
SELECTCAST(1ASInt32?), -- тоже что и Just(1)CAST(Just(2/1) ASFloat??), -- [2]CAST(Just(3/0) ASFloat??) ISNULL; -- false: результат Just(NULL)
Правила для List/Dict
Список формируется путём выполнения CAST для каждого элемента исходного списка в тип элемента целевого типа.
Если тип элемента целевого типа не опциональный, а CAST элемента может быть неуспешным, то такие преобразования отбрасываются. В этом случае список в результате может быть меньшей длины или вовсе пустой, если успешных преобразований не было.
Для словарей преобразование выполняется полностью аналогично спискам, выполняя CAST для ключей и значений.
Структура или кортеж формируется путём выполнения CAST для каждого элемента исходного типа в элемент с тем же именем или индексом целевого типа.
Если какое-то поле отсутствует в целевом типе, оно просто отбрасывается.
Если какое-то поле отсутствует в типе исходного значения, то оно может быть добавлено только если является опциональным, и получает значение NULL.
Если какое-то поле не является опциональным в целевом типе, но его преобразование может быть неуспешным, то CAST добавляет опциональность на уровень структуры или кортежа и может вернуть NULL для всего результата.
SELECTCAST((-1, 0, 1) AS Tuple<Uint16?, Uint16?, Utf8>), -- (null, 0, "1")CAST((-2, 0) AS Tuple<Uint16, Utf8>), -- nullCAST((3, 4) AS Tuple<Uint16, String>), -- (3, "4") тип Tuple<Uint16, String>?CAST(("4",) AS Tuple<Uint16, String?>), -- (4, null)CAST((5, 6, null) AS Tuple<Uint8?>); -- (5,) элементы удалены.SELECT-- Одно поле удалено и одно добавлено: ("three":null, "two": "42")CAST(<|one:"8912", two:42|> AS Struct<two:Utf8, three:Date?>);
Правила для Variant
Для варианта с определёнными именем или индексом выполняется преобразование в вариант с тем же именем или индексом.
Если преобразование для варианта может быть неуспешным и тип этого варианта не опциональный, то CAST добавляет опциональность на верхний уровень и может вернуть NULL.
Если какой-то вариант отсутствует в целевом типе, то CAST добавляет опциональность на верхний уровень и для такого значения возвращает NULL.
Вложенные контейнеры
Все вышеперечисленные правила работают рекурсивно для вложенных контейнеров.