Hologres兼容PostgreSQL 11,支持通过CAST、::、TRY_CAST以及TO_CHAR等格式化函数在数据类型之间转换。本文介绍各转换方式的语法、行为差异和选用建议。
类型转换函数列表
Hologres支持以下类型转换函数和运算符。各转换方式的行为差异和使用示例,请参见后续章节。
|
函数或运算符 |
语法 |
作用 |
详情 |
|
|
|
标准SQL写法,将表达式转换为指定的目标类型。 |
|
|
|
|
PostgreSQL简写,效果与 |
|
|
|
将TEXT类型数据转换为目标类型,数据不符合目标类型约束时返回NULL。 |
||
|
|
按模板串将数值或日期时间转换为字符串。 |
||
|
|
按模板串将字符串转换为NUMERIC。 |
||
|
|
按模板串将字符串转换为DATE。 |
||
|
|
按模板串将字符串转换为TIMESTAMPTZ。 |
转换方式概览
Hologres提供以下三类数据类型转换方式,区别主要在于转换失败时的行为。
|
转换方式 |
转换失败时的行为 |
适用场景 |
|
显式转换 |
报错,整条查询失败 |
数据已清洗、类型确定,希望脏数据尽早暴露。 |
|
容错转换 |
返回NULL,查询继续执行 |
数据源含脏数据,需要跳过异常值继续处理。 |
|
格式化转换 |
报错,整条查询失败 |
需要按指定格式在字符串与数值、日期时间之间转换。 |
关于Hologres支持的数据类型,请参见数据类型汇总。
显式转换
显式转换通过CAST函数或::运算符完成。CAST(expr AS type)是标准SQL写法,expr::type是PostgreSQL简写,两者效果完全相同。
常用转换示例如下。
-- 字符串转整数,两种写法等价,均返回 123
SELECT CAST('123' AS int);
SELECT '123'::int;
-- 整数转字符串,返回 123
SELECT CAST(123 AS text);
-- 字符串转 NUMERIC,返回 12.34
SELECT CAST('12.34' AS numeric);
-- 字符串转布尔,返回 t(即true,PostgreSQL布尔类型的默认显示形式)
SELECT CAST('true' AS boolean);
-- 字符串转日期,返回 2026-08-13
SELECT CAST('2026-08-13' AS date);
-- 字符串转 JSONB,返回 {"a": 1}
SELECT CAST('{"a":1}' AS jsonb);
-- 布尔转整数,返回 1
SELECT CAST(true AS int);
浮点数与NUMERIC转整数的舍入差异
将小数转换为整数时,源类型不同,舍入规则也不同:
-
DOUBLE PRECISION、REAL转整数:采用四舍六入五成双(银行家舍入),即小数部分正好为0.5时向最近的偶数取整。
-
NUMERIC、DECIMAL转整数:采用四舍五入,小数部分为0.5时向绝对值更大的方向取整。
因此同为2.5,转换结果可能不同。
-- 返回 2(2.5 向最近的偶数 2 取整)
SELECT CAST(2.5::float8 AS int);
-- 返回 4(3.5 向最近的偶数 4 取整)
SELECT CAST(3.5::float8 AS int);
-- 返回 3(四舍五入)
SELECT CAST(2.5::numeric AS int);
ROUND函数对DOUBLE PRECISION同样采用四舍六入五成双,因此直接用ROUND并不能改变舍入结果,ROUND(2.5::float8)返回2。如需四舍五入,请先转换为NUMERIC再取整,ROUND(2.5::float8::numeric)返回3。
转换失败时的报错
使用CAST时,只要有一行数据无法转换,整条查询即失败。常见报错如下。
|
场景 |
报错信息 |
处理建议 |
|
字符串不符合目标类型格式,例如将 |
|
改用TRY_CAST将异常值转为NULL,或先在数据清洗阶段过滤脏数据。 |
|
带小数的字符串转整数,例如将 |
|
先转为NUMERIC再转为INT,例如 |
|
字符串表示的数值超出目标类型取值范围,例如将 |
|
改用取值范围更大的目标类型,例如BIGINT。 |
|
数值超出目标类型取值范围,例如将BIGINT最大值转为SMALLINT。 |
|
改用取值范围更大的目标类型,例如BIGINT。 |
容错转换
容错转换通过TRY_CAST函数完成,用于将TEXT类型数据转换为目标类型。当数据不符合目标类型约束时返回NULL而不抛出异常,适合处理含脏数据的数据源。语法、支持的目标类型及版本要求,请参见类型转换函数。
TRY_CAST的容错能力仅对表中的列数据生效。如果直接对字符串常量使用TRY_CAST,常量会在查询计划阶段被求值,仍然会报错。例如SELECT TRY_CAST('abc' AS int);会返回ERROR: invalid input syntax for integer: "abc"。验证TRY_CAST行为时,请将数据写入表后再查询。
此外,未标注类型的字符串常量属于unknown类型,即使数据合法也会报错。例如SELECT TRY_CAST('123' AS int);会返回ERROR: cannot try cast type unknown to integer。如需对常量试用,请显式标注类型,例如SELECT TRY_CAST('123'::text AS int);。
使用TRY_CAST时存在以下类型限制。
-
源类型必须为TEXT:对其他源类型使用TRY_CAST会直接报错
ERROR: cannot try cast type <源类型> to <目标类型>,而不是返回NULL。例如对NUMERIC列使用TRY_CAST会报ERROR: cannot try cast type numeric to integer。此类场景请改用CAST或::。 -
部分目标类型不支持:目标类型为TEXT或JSON时会报错
ERROR: cannot try cast type ...,而不是返回NULL。
以下示例构造一张含脏数据的表,对比CAST与TRY_CAST的差异。
CREATE TABLE type_convert_test (
k int,
v text
);
INSERT INTO type_convert_test VALUES
(1, '123'),
(2, 'abc'),
(3, '12.7'),
(4, ''),
(5, NULL);
使用TRY_CAST转换,异常值统一返回NULL。
SELECT k, v,
TRY_CAST(v AS int) AS v_int,
TRY_CAST(v AS numeric) AS v_numeric
FROM type_convert_test
ORDER BY k;
返回结果如下。
k | v | v_int | v_numeric
---+------+-------+-------------------
1 | 123 | 123 | 123.000000000000000
2 | abc | |
3 | 12.7 | | 12.700000000000000
4 | | |
5 | | |
(5 rows)
使用TRY_CAST时请注意以下行为。
-
不做截断或舍入:带小数的字符串转整数时返回NULL,而非取整。例如上例中
12.7转INT返回NULL。如需保留数值,请先转为NUMERIC。 -
数值溢出同样返回NULL:源数据超出目标类型取值范围时返回NULL,不报错。
-
空字符串返回NULL:空字符串不符合数值、日期等类型的格式,转换结果为NULL。
-
转NUMERIC或DECIMAL时保留15位小数:如需固定小数位数,请显式指定精度,例如
TRY_CAST(v AS numeric)::numeric(10,2)。 -
转DATE时截断时间部分:例如
2026-08-13 10:20:30转DATE返回2026-08-13。
格式化转换
格式化转换通过TO_CHAR、TO_NUMBER、TO_DATE和TO_TIMESTAMP函数完成。这些函数兼容PostgreSQL,可按模板串在字符串与数值、日期时间之间转换:TO_CHAR将数值或日期时间输出为指定格式的字符串,TO_NUMBER、TO_DATE和TO_TIMESTAMP则按模板串将字符串解析为NUMERIC、DATE和TIMESTAMPTZ。
TO_TIMESTAMP返回的是TIMESTAMPTZ(带时区的时间戳),结果中会包含时区偏移(例如+08),且显示结果随Session的时区设置变化。如果需要不带时区的TIMESTAMP,请再显式转换,例如TO_TIMESTAMP(...)::timestamp。
日期时间相关函数的完整语法、模板串说明及版本限制,请参见日期和时间函数。
数值模板串示例
常用数值模板串的效果如下。
-- 返回 ' 125',模板首位预留符号位,正数显示为空格
SELECT TO_CHAR(125, '999');
-- 返回 ' 0125',用 0 补足位数
SELECT TO_CHAR(125, '0999');
-- 返回 ' 1,234',按千分位分组
SELECT TO_CHAR(1234, '9,999');
-- 返回 '125',FM 前缀去除填充空格
SELECT TO_CHAR(125, 'FM999');
-- 返回 '-125',S 显示符号
SELECT TO_CHAR(-125, 'S999');
-- 返回 '125-',MI 将负号显示在末尾
SELECT TO_CHAR(-125, '999MI');
-- L 显示货币符号,符号取决于实例的 lc_monetary 设置
-- lc_monetary 为 en_US.UTF-8 时返回 '$ 125',可执行 SHOW lc_monetary; 查看当前实例的设置
SELECT TO_CHAR(125, 'L999');
-- 返回 ' 1.23e+03',EEEE 输出科学计数法
SELECT TO_CHAR(1234.5, '9.99EEEE');
-- 返回 -12454.8,按模板解析千分位与尾部负号
SELECT TO_NUMBER('12,454.8-', '99G999D9S');
模板串的整数位数必须能容纳待转换的数值,否则整数部分会被替换为#。例如TO_CHAR(125.8, '99D9')中模板只有两位整数位,无法容纳三位整数,返回' ##.#';改用TO_CHAR(125.8, '999D9')可返回' 125.8'。
选用建议
-
数据已清洗、字段类型可控时优先使用
::或CAST,脏数据能第一时间暴露,避免错误被NULL掩盖。 -
从日志、埋点等非结构化来源导入的TEXT字段,使用TRY_CAST跳过异常值,并配合
COUNT统计NULL数量监控脏数据比例。 -
需要控制输出格式(补零、千分位、货币符号、科学计数法)时使用TO_CHAR,不要用字符串拼接自行拼装。
-
转换操作会带来额外计算开销,对于高频查询的字段,建议在写入时就存储为目标类型,而不是每次查询时转换。