跳到主要内容

Typecasting

类型转换是一种将某种数据类型中的值转换为另一种数据类型中最接近对应值的操作。 与其他 SQL 引擎类似,Goose 同时支持隐式和显式类型转换。

显式类型转换

显式类型转换通过 CAST 表达式执行。例如,CAST(col AS VARCHAR)col::VARCHAR 会将列 col 显式转换为 VARCHAR。更多信息请参见 cast page

隐式类型转换

在许多情况下,系统会自行添加类型转换。这称为隐式类型转换,例如当调用函数时传入的参数类型与函数要求不匹配,但可以转换为所需类型。

隐式类型转换只能用于部分类型组合,并且通常仅在转换不会失败时才可进行。例如,可以从 INTEGER 隐式转换到 DOUBLE,但不能从 DOUBLE 隐式转换到 INTEGER

以函数 sin(DOUBLE) 为例。该函数需要 DOUBLE 类型参数,但也可以用整数调用:sin(1)。在传给 sin 函数之前,整数会先被转换为 double。

Tip 要检查某个类型能否隐式转换为另一种类型,请使用 can_cast_implicitly function

组合类型转换

当不同类型的值需要合并为一个未明确指定的共同父类型时,系统会执行隐式转换到自动选择的父类型。例如,list_value(1::INT64, 1::UINT64) 会创建类型为 INT128[] 的列表。在这种场景下执行的隐式转换有时比常规隐式转换更宽松。例如,BOOL 值可以被转换为 INTtrue 映射为 1false 映射为 0),即使这在常规隐式转换中并不允许。

这种组合类型转换会出现在比较(= / < / >)、集合操作(UNION / EXCEPT / INTERSECT)以及嵌套类型构造器(list_value / [...] / MAP)中。

类型转换矩阵

某一特定数据类型的值并不总是能转换为任意目标数据类型。唯一例外是 NULL 值,它始终可以在类型之间转换。 下表描述了哪些转换是受支持的。 当允许隐式转换时,也意味着显式转换同样可行。

Typecasting matrix

即使根据源类型和目标类型该转换操作受支持,也不意味着它在运行时一定会成功。

Deprecated 在 0.10.0 之前,Goose 在函数绑定期间允许任意类型隐式转换为 VARCHAR。 0.10.0 引入了不兼容变更,不再允许隐式转换到 VARCHAR。 可通过 old_implicit_casting configuration option 设置恢复旧行为。 但请注意,该标志未来将被弃用。

有损转换

允许会导致精度损失的转换操作。例如,可以将带小数位的数值类型(如 DECIMALFLOATDOUBLE)显式转换为整数类型(如 INTEGERBIGINT)。数值会被四舍五入。

SELECT CAST(3.1 AS INTEGER);  -- 3
SELECT CAST(3.5 AS INTEGER); -- 4
SELECT CAST(-1.7 AS INTEGER); -- -2

溢出

会导致数值溢出的转换操作会抛出错误。例如,值 999 对于 TINYINT 数据类型来说过大,无法表示。因此,将该值转换为该类型会导致运行时错误:

SELECT CAST(999 AS TINYINT);
Conversion Error:
Type INT32 with value 999 can't be cast because the value is out of range for the destination type INT8

因此,尽管从 INTEGERTINYINT 的转换操作是受支持的,但对这个特定值并不可行。可使用 TRY_CAST 将该值转换为 NULL,而不是抛出错误。

Varchar

VARCHAR 类型可作为通用目标:任意类型的任意值都始终可以转换为 VARCHAR。该类型也用于在 shell 中显示值。

SELECT CAST(42.5 AS VARCHAR);

支持从 VARCHAR 转换到其他数据类型,但如果 Goose 无法将提供的文本解析并转换为目标数据类型,运行时可能会报错。

SELECT CAST('NotANumber' AS INTEGER);

通常,将值转换为 VARCHAR 是无损操作,任意类型在转换为文本后都可以再转换回原始类型。

SELECT CAST(CAST([1, 2, 3] AS VARCHAR) AS INTEGER[]);

字面量类型

整数字面量(如 42)和字符串字面量(如 'string')具有特殊的隐式转换规则。更多信息请参见 literal types page

列表 / 数组

列表可以按照相同的转换规则显式转换为其他列表。转换会应用到列表中的子元素。例如,将 INTEGER[] 列表转换为 VARCHAR[] 列表时,子元素 INTEGER 会逐个转换为 VARCHAR,并构造出新的列表。

SELECT CAST([1, 2, 3] AS VARCHAR[]);

数组

数组遵循与列表相同的转换规则。此外,数组还可以隐式转换为相同类型的列表。例如,INTEGER[3] 数组可以隐式转换为 INTEGER[] 列表。

Structs

只要至少共享一个字段,struct 就可以转换为其他 struct。

这一要求的目的是避免非预期错误。如果两个 struct 没有任何共同字段,那么该转换很可能并非本意。

SELECT CAST({'a': 42} AS STRUCT(a VARCHAR));

目标 struct 中存在但源 struct 中不存在的字段,默认值为 NULL

SELECT CAST({'a': 42} AS STRUCT(a VARCHAR, b VARCHAR));

仅存在于源 struct 中的字段会被忽略。

SELECT CAST({'a': 42, 'b': 43} AS STRUCT(a VARCHAR));

struct 字段名也可以使用不同顺序。struct 的字段会根据字段名重新排列。

SELECT CAST({'a': 42, 'b': 84} AS STRUCT(b VARCHAR, a VARCHAR));

对于 combination casting,结果 struct 的字段是所有输入 struct 字段的并集(超集)。 该逻辑同样会递归应用到可能存在的嵌套 struct。

SELECT {'outer1': {'inner1': 42, 'inner2': 42}} AS c
UNION
SELECT {'outer1': {'inner2': 'hello', 'inner3': 'world'}, 'outer2': '100'} AS c;
SELECT [{'a': 42}, {'b': 84}];

Unions

Union 的转换规则见 UNION type page