Skip to content

PostgreSQL 数据类型格式化函数

PostgreSQL 提供了一组强大的格式化函数,用于在各种数据类型(日期/时间、整数、浮点数、数值)与格式化字符串之间进行转换。这些函数在数据展示、报表生成和数据清洗中发挥着重要作用。

格式化函数概述

所有格式化函数都遵循统一的调用约定:

  • 第一个参数:要格式化的值
  • 第二个参数:定义输出或输入格式的模板字符串

核心格式化函数

函数功能对比表

函数签名功能描述使用场景
to_char(timestamp, text)时间戳转字符串报表显示、日志格式化
to_char(interval, text)时间间隔转字符串持续时间显示
to_char(numeric_type, text)数值转字符串金额格式化、统计报表
to_date(text, text)字符串转日期数据导入、格式标准化
to_number(text, text)字符串转数值数据清洗、类型转换
to_timestamp(text, text)字符串转时间戳日志解析、数据同步

TIP

对于标准的日期/时间和数值格式,建议直接使用类型转换,更简单高效。格式化函数主要用于处理非标准格式的数据。

日期时间格式化

基础时间格式模式

时间组件模式

模式描述示例输出
HH12 小时制小时 (01–12)05
HH2424 小时制小时 (00–23)17
MI分钟 (00–59)31
SS秒 (00–59)12
MS毫秒 (000–999)066
US微秒 (000000–999999)066000

日期组件模式

模式描述示例输出
YYYY4 位年份2002
MM月份编号 (01–12)04
DD日期 (01–31)20
DY星期几缩写Sat
MONTH完整月份名APRIL

实际应用示例

示例 1:生成用户友好的时间显示

问题陈述:在电商系统中,需要为订单显示易读的时间格式。

解决方案

sql
-- 订单时间格式化
SELECT
    order_id,
    created_at,
    to_char(created_at, 'YYYY年MM月DD日 HH24:MI') AS 显示时间,
    to_char(created_at, 'Dy') AS 星期几
FROM orders
WHERE order_id = 12345;

输入数据

sql
order_id: 12345
created_at: 2024-03-15 14:30:25

预期输出

order_id | created_at          | 显示时间           | 星期几
---------|--------------------|--------------------|--------
12345    | 2024-03-15 14:30:25| 2024年03月15日 14:30| Fri

分析过程

  • YYYY年MM月DD日:创建中文日期格式
  • HH24:MI:使用 24 小时制显示时分
  • Dy:显示星期几的英文缩写

示例 2:时间间隔的人性化显示

问题陈述:显示任务执行时长,让用户直观了解处理耗时。

解决方案

sql
-- 任务执行时长格式化
SELECT
    task_name,
    start_time,
    end_time,
    end_time - start_time AS duration_interval,
    to_char(end_time - start_time, 'HH24:MI:SS') AS 执行时长
FROM task_logs
WHERE DATE(start_time) = CURRENT_DATE;

输入数据

sql
task_name: 数据备份
start_time: 2024-03-15 02:00:00
end_time: 2024-03-15 04:15:30

预期输出

task_name | start_time          | end_time            | duration_interval | 执行时长
----------|--------------------|--------------------|-------------------|----------
数据备份   | 2024-03-15 02:00:00| 2024-03-15 04:15:30| 02:15:30         | 02:15:30

字符串转日期的应用

示例 3:处理多种日期格式的数据导入

问题陈述:从外部系统导入用户数据,日期格式不统一,需要标准化处理。

解决方案

sql
-- 处理不同格式的日期字符串
WITH import_data AS (
    SELECT '05 Dec 2000' as date_str, 'DD Mon YYYY' as format_pattern
    UNION ALL
    SELECT '2000/12/05', 'YYYY/MM/DD'
    UNION ALL
    SELECT '12-05-2000', 'MM-DD-YYYY'
)
SELECT
    date_str AS 原始格式,
    format_pattern AS 格式模式,
    to_date(date_str, format_pattern) AS 标准日期
FROM import_data;

预期输出

原始格式      | 格式模式      | 标准日期
-------------|-------------|----------
05 Dec 2000  | DD Mon YYYY | 2000-12-05
2000/12/05   | YYYY/MM/DD  | 2000-12-05
12-05-2000   | MM-DD-YYYY  | 2000-12-05

分析过程

  • DD Mon YYYY:处理"日 月名 年"格式
  • YYYY/MM/DD:处理 ISO 标准斜杠分隔格式
  • MM-DD-YYYY:处理美式日期格式
  • 所有格式最终转换为标准的YYYY-MM-DD格式

格式模式修饰符

修饰符功能说明

修饰符功能应用示例
FM去除填充零和空格FMMonthMarch而非March
TH添加序数后缀DDTH15th
FX严格匹配格式要求输入严格按模板格式
TM本地化模式根据lc_time设置显示本地语言

示例 4:灵活的日期格式输出

问题陈述:为不同地区用户提供本地化的日期显示。

解决方案

sql
-- 多种格式的日期显示
SELECT
    CURRENT_DATE as 当前日期,
    to_char(CURRENT_DATE, 'Month DD, YYYY') AS 标准格式,
    to_char(CURRENT_DATE, 'FMMonth DD, YYYY') AS 无填充格式,
    to_char(CURRENT_DATE, 'DDth "of" FMMonth, YYYY') AS 序数格式,
    to_char(CURRENT_DATE, 'TMMonth DD, YYYY') AS 本地化格式;

分析过程

  • 标准格式:March 15, 2024(月份名用空格填充到 9 字符)
  • 无填充格式:March 15, 2024(去除多余空格)
  • 序数格式:15th of March, 2024(添加序数词和介词)
  • 本地化格式:根据系统 locale 设置显示

WARNING

使用FX修饰符时,输入字符串必须严格匹配模板格式,包括空格和分隔符的数量。

数值格式化

数值格式模式

模式功能示例
9数字位(可省略前导零)999 12
0数字位(保留前导零)000012
,千位分隔符9,9991,234
.小数点99.9912.34
$货币符号$999$123
PR负数括号表示999PR<123>
S正负号S999+123

实际应用示例

示例 5:财务报表金额格式化

问题陈述:财务系统需要按照会计标准显示金额,包括千位分隔符、货币符号和负数处理。

解决方案

sql
-- 财务金额格式化
WITH financial_data AS (
    SELECT 1234567.89 AS amount, '销售收入' AS item_type
    UNION ALL
    SELECT -45678.50, '销售退款'
    UNION ALL
    SELECT 0.05, '银行利息'
)
SELECT
    item_type AS 项目类型,
    amount AS 原始金额,
    to_char(amount, '$999,999,999.99') AS 标准格式,
    to_char(amount, '$999,999,999.99PR') AS 负数括号格式,
    to_char(amount, 'L999,999,999.99') AS 本地货币格式
FROM financial_data;

预期输出

项目类型 | 原始金额    | 标准格式        | 负数括号格式      | 本地货币格式
--------|------------|----------------|------------------|----------------
销售收入 | 1234567.89 | $1,234,567.89  | $1,234,567.89    | ¥1,234,567.89
销售退款 | -45678.50  | $  -45,678.50  | $<45,678.50>     | ¥  -45,678.50
银行利息 | 0.05       | $        0.05  | $        0.05    | ¥        0.05

示例 6:科学计数法格式化

问题陈述:在科学计算或数据分析中,需要将大数值以科学计数法显示。

解决方案

sql
-- 科学计数法格式化
SELECT
    12345678.9 AS 原始数值,
    to_char(12345678.9, '9.99EEEE') AS 科学计数法,
    to_char(0.000123, '9.99EEEE') AS 小数科学计数法;

预期输出

原始数值      | 科学计数法   | 小数科学计数法
-------------|-------------|---------------
12345678.9   | 1.23E+07    | 1.23E-04

字符串转数值的应用

示例 7:清洗带格式的数值数据

问题陈述:从 CSV 文件导入的财务数据包含千位分隔符和货币符号,需要转换为数值类型进行计算。

解决方案

sql
-- 带格式字符串转数值
WITH raw_data AS (
    SELECT '$12,454.80' AS amount_str, '99G999D99' AS format_pattern
    UNION ALL
    SELECT '12,454.8-', '99G999D9S'
    UNION ALL
    SELECT '(1,234.56)', '999G999D99PR'
)
SELECT
    amount_str AS 原始字符串,
    format_pattern AS 格式模式,
    to_number(amount_str, format_pattern) AS 转换后数值,
    to_number(amount_str, format_pattern) * 1.1 AS 加税后金额
FROM raw_data;

预期输出

原始字符串   | 格式模式     | 转换后数值 | 加税后金额
------------|-------------|-----------|----------
$12,454.80  | 99G999D99   | 12454.80  | 13700.28
12,454.8-   | 99G999D9S   | -12454.8  | -13700.28
(1,234.56)  | 999G999D99PR| -1234.56  | -1358.02

分析过程

  • G:千位分隔符(使用 locale 设置)
  • D:小数点(使用 locale 设置)
  • S:正负号标识
  • PR:括号表示负数

高级应用场景

复杂业务场景示例

示例 8:多时区时间处理

问题陈述:国际化应用需要将 UTC 时间转换为不同时区的本地时间显示。

解决方案

sql
-- 多时区时间格式化
WITH timezone_data AS (
    SELECT
        '2024-03-15 08:30:00'::timestamp AS utc_time,
        'UTC' AS source_tz
)
SELECT
    utc_time AS UTC时间,
    to_char(utc_time AT TIME ZONE 'Asia/Shanghai', 'YYYY-MM-DD HH24:MI:SS TZ') AS 北京时间,
    to_char(utc_time AT TIME ZONE 'America/New_York', 'YYYY-MM-DD HH24:MI:SS TZ') AS 纽约时间,
    to_char(utc_time AT TIME ZONE 'Europe/London', 'YYYY-MM-DD HH24:MI:SS TZ') AS 伦敦时间
FROM timezone_data;

示例 9:动态报表格式化

问题陈述:根据数值大小动态选择最适合的显示格式。

解决方案

sql
-- 动态数值格式化
WITH sales_data AS (
    SELECT 1250000 AS amount, '大额销售' AS category
    UNION ALL
    SELECT 1250 AS amount, '普通销售' AS category
    UNION ALL
    SELECT 12.5 AS amount, '小额销售' AS category
)
SELECT
    category AS 类别,
    amount AS 原始金额,
    CASE
        WHEN amount >= 1000000 THEN to_char(amount/10000, 'FM999.9') || '万'
        WHEN amount >= 1000 THEN to_char(amount, 'FM9,999')
        ELSE to_char(amount, 'FM999.99')
    END AS 格式化显示
FROM sales_data;

预期输出

类别     | 原始金额 | 格式化显示
---------|---------|----------
大额销售 | 1250000 | 125万
普通销售 | 1250    | 1,250
小额销售 | 12.5    | 12.5

格式化函数的性能考虑

TIP

性能优化建议

  1. 大数据集处理:考虑在应用层而非数据库层进行格式化
  2. 索引利用:避免在 WHERE 子句中对索引列使用格式化函数
  3. 缓存策略:对于静态格式化结果,考虑使用缓存
  4. 批量处理:使用 CASE 语句进行条件格式化,减少函数调用次数

常见错误处理

格式不匹配错误

WARNING

常见错误

sql
-- 错误示例:格式不匹配
SELECT to_date('2024-13-45', 'YYYY-MM-DD');
-- ERROR: date/time field value out of range

-- 正确处理方式
SELECT
    CASE
        WHEN date_str ~ '^\d{4}-\d{2}-\d{2}$'
        THEN to_date(date_str, 'YYYY-MM-DD')
        ELSE NULL
    END AS parsed_date
FROM import_table;

数值溢出处理

sql
-- 安全的数值转换
CREATE OR REPLACE FUNCTION safe_to_number(
    input_text TEXT,
    format_text TEXT DEFAULT NULL
) RETURNS NUMERIC AS $$
BEGIN
    IF format_text IS NULL THEN
        RETURN input_text::NUMERIC;
    ELSE
        RETURN to_number(input_text, format_text);
    END IF;
EXCEPTION
    WHEN OTHERS THEN
        RETURN NULL;
END;
$$ LANGUAGE plpgsql;

总结

PostgreSQL 的格式化函数提供了强大而灵活的数据转换能力:

  1. 统一接口:所有函数采用相同的参数模式
  2. 丰富模板:支持详细的格式控制
  3. 本地化支持:自动适应不同 locale 设置
  4. 业务适用性:满足报表、数据清洗、国际化等需求

通过合理使用这些函数,可以实现高质量的数据展示和灵活的数据处理,但需要注意性能影响和错误处理。

INFO

最佳实践

  • 优先使用标准类型转换,格式化函数用于特殊需求
  • 在生产环境中添加适当的错误处理机制
  • 考虑将复杂格式化逻辑封装为函数
  • 定期检查和优化格式化相关的查询性能