数据类型转换

更新时间:
复制 MD 格式

Hologres兼容PostgreSQL 11,支持通过CAST、::、TRY_CAST以及TO_CHAR等格式化函数在数据类型之间转换。本文介绍各转换方式的语法、行为差异和选用建议。

类型转换函数列表

Hologres支持以下类型转换函数和运算符。各转换方式的行为差异和使用示例,请参见后续章节。

函数或运算符

语法

作用

详情

CAST

CAST(expr AS type)

标准SQL写法,将表达式转换为指定的目标类型。

显式转换

::

expr::type

PostgreSQL简写,效果与CAST完全相同。

显式转换

TRY_CAST

TRY_CAST(expr AS type)

将TEXT类型数据转换为目标类型,数据不符合目标类型约束时返回NULL。

容错转换

TO_CHAR

TO_CHAR(value, format)

按模板串将数值或日期时间转换为字符串。

格式化转换

TO_NUMBER

TO_NUMBER(text, format)

按模板串将字符串转换为NUMERIC。

格式化转换

TO_DATE

TO_DATE(text, format)

按模板串将字符串转换为DATE。

格式化转换

TO_TIMESTAMP

TO_TIMESTAMP(text, format)

按模板串将字符串转换为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时,只要有一行数据无法转换,整条查询即失败。常见报错如下。

场景

报错信息

处理建议

字符串不符合目标类型格式,例如将not-a-value转为INT。

ERROR: invalid input syntax for integer: "not-a-value"

改用TRY_CAST将异常值转为NULL,或先在数据清洗阶段过滤脏数据。

带小数的字符串转整数,例如将1.25转为INT。

ERROR: invalid input syntax for integer: "1.25"

先转为NUMERIC再转为INT,例如'1.25'::numeric::int。

字符串表示的数值超出目标类型取值范围,例如将'9223372036854775807'转为SMALLINT。

ERROR: value "9223372036854775807" is out of range for type smallint

改用取值范围更大的目标类型,例如BIGINT。

数值超出目标类型取值范围,例如将BIGINT最大值转为SMALLINT。

ERROR: smallint out of range

改用取值范围更大的目标类型,例如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,不要用字符串拼接自行拼装。

  • 转换操作会带来额外计算开销,对于高频查询的字段,建议在写入时就存储为目标类型,而不是每次查询时转换。