类型转换是一种操作,它将一个特定数据类型的值转换为另一个数据类型中最接近的对应值。 与其他SQL引擎一样,DuckDB支持隐式和显式类型转换。
显式类型转换
显式类型转换是通过使用CAST
表达式来执行的。例如,CAST(col AS VARCHAR)
或col::VARCHAR
显式地将列col
转换为VARCHAR
。有关更多信息,请参阅cast页面。
隐式类型转换
在许多情况下,系统会自动添加类型转换。这被称为隐式转换,例如,当调用函数时,如果参数的类型与函数的类型不匹配,但可以转换为所需的类型时,就会发生这种情况。
隐式转换只能为某些类型组合添加,通常只有在转换不会失败时才可能。例如,可以从INTEGER
到DOUBLE
添加隐式转换——但不能从DOUBLE
到INTEGER
。
考虑函数 sin(DOUBLE)
。该函数接受一个类型为 DOUBLE
的列作为输入参数,然而,它也可以用整数调用:sin(1)
。在传递给 sin
函数之前,整数会被转换为双精度浮点数。
组合铸造
当需要将不同类型的值组合到一个未指定的联合父类型时,系统将执行隐式转换以自动选择父类型。例如,list_value(1::INT64, 1::UINT64)
创建了一个类型为 INT128[]
的列表。在这种情况下执行的隐式转换有时比常规的隐式转换更为宽松。例如,BOOL
值可能会被转换为 INT
(其中 true
映射为 1
,false
映射为 0
),尽管这在常规的隐式转换中是不可能的。
这种组合转换发生在比较操作(==
/ <
/ >
)、集合操作(UNION
/ EXCEPT
/ INTERSECT
)以及嵌套类型构造函数(list_value
/ [...]
/ MAP
)中。
类型转换操作矩阵
特定数据类型的值不能总是转换为任意目标数据类型。唯一的例外是NULL
值——它可以在类型之间进行转换。
以下矩阵描述了哪些转换是支持的。
当允许隐式转换时,意味着显式转换也是可能的。
尽管根据源数据类型和目标数据类型支持转换操作,但这并不一定意味着转换操作在运行时一定会成功。
在0.10.0版本之前,DuckDB允许在函数绑定期间将任何类型隐式转换为
VARCHAR
。 0.10.0版本引入了一个不再允许隐式转换为VARCHAR
的重大更改。 可以使用old_implicit_casting
配置选项设置来恢复到旧的行为。 但是,请注意,此标志将在未来被弃用。
有损转换
允许导致精度损失的转换操作。例如,可以显式地将具有小数位的数字类型(如DECIMAL
、FLOAT
或DOUBLE
)转换为整数类型(如INTEGER
)。数字将被四舍五入。
SELECT CAST(3.5 AS INTEGER);
溢出
会导致值溢出的转换操作会抛出错误。例如,值 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
因此,即使支持从INTEGER
到TINYINT
的转换操作,对于这个特定的值来说是不可能的。TRY_CAST可以用来将值转换为NULL
,而不是抛出错误。
Varchar
VARCHAR
类型充当通用目标:任何类型的任意值都可以转换为 VARCHAR
类型。此类型也用于在 shell 中显示值。
SELECT CAST(42.5 AS VARCHAR);
从VARCHAR
转换为其他数据类型是支持的,但如果DuckDB无法解析并将提供的文本转换为目标数据类型,则可能在运行时引发错误。
SELECT CAST('NotANumber' AS INTEGER);
通常,转换为VARCHAR
是一种无损操作,任何类型在转换为文本后都可以转换回原始类型。
SELECT CAST(CAST([1, 2, 3] AS VARCHAR) AS INTEGER[]);
Literal Types
整数字面量(如42
)和字符串字面量(如'string'
)有特殊的隐式转换规则。更多信息请参见字面量类型页面。
列表 / 数组
列表可以使用相同的转换规则显式转换为其他列表。转换应用于列表的子元素。例如,如果我们将一个INTEGER[]
列表转换为一个VARCHAR[]
列表,子元素INTEGER
会单独转换为VARCHAR
,并构建一个新的列表。
SELECT CAST([1, 2, 3] AS VARCHAR[]);
Arrays
数组遵循与列表相同的类型转换规则。此外,数组可以隐式转换为相同类型的列表。例如,一个INTEGER[3]
数组可以隐式转换为一个INTEGER[]
列表。
Structs
只要子元素的名称匹配,结构体可以转换为其他结构体。
SELECT CAST({'a': 42} AS STRUCT(a VARCHAR));
结构体的名称也可以以不同的顺序排列。结构体的字段将根据结构体的名称重新排列。
SELECT CAST({'a': 42, 'b': 84} AS STRUCT(b VARCHAR, a VARCHAR));
联合
联合类型的转换规则可以在UNION type page
上找到。