【AI大数据工程师特训笔记】第04讲:PostgreSQL 数据库内置函数详解

目录

第零章:环境准备:保险业务数据模型

[第一章 字符串函数](#第一章 字符串函数)

[1.1 CONCAT 与 CONCAT_WS](#1.1 CONCAT 与 CONCAT_WS)

[1.2 SUBSTRING](#1.2 SUBSTRING)

[1.3 UPPER / LOWER / INITCAP](#1.3 UPPER / LOWER / INITCAP)

[1.4 LENGTH](#1.4 LENGTH)

[1.5 TRIM(及 LTRIM / RTRIM)](#1.5 TRIM(及 LTRIM / RTRIM))

[1.6 REPLACE](#1.6 REPLACE)

[1.7 POSITION / STRPOS](#1.7 POSITION / STRPOS)

[1.8 LEFT / RIGHT](#1.8 LEFT / RIGHT)

[1.9 正则表达式函数](#1.9 正则表达式函数)

[1.9.1 REGEXP_MATCHES](#1.9.1 REGEXP_MATCHES)

[1.9.2 REGEXP_REPLACE](#1.9.2 REGEXP_REPLACE)

[第二章 数值函数](#第二章 数值函数)

[2.1 ROUND](#2.1 ROUND)

[2.2 TRUNC](#2.2 TRUNC)

[2.3 CEIL / FLOOR](#2.3 CEIL / FLOOR)

[2.4 MOD](#2.4 MOD)

[2.5 ABS](#2.5 ABS)

[2.6 POWER / SQRT](#2.6 POWER / SQRT)

[2.7 RANDOM](#2.7 RANDOM)

[第三章 日期/时间函数](#第三章 日期/时间函数)

[3.1 CURRENT_DATE / CURRENT_TIMESTAMP / NOW](#3.1 CURRENT_DATE / CURRENT_TIMESTAMP / NOW)

[3.2 EXTRACT / DATE_PART](#3.2 EXTRACT / DATE_PART)

[3.3 AGE](#3.3 AGE)

[3.4 DATE_TRUNC](#3.4 DATE_TRUNC)

[3.5 TO_CHAR(日期格式化)](#3.5 TO_CHAR(日期格式化))

[第四章 条件判断函数](#第四章 条件判断函数)

[4.1 CASE WHEN](#4.1 CASE WHEN)

[4.2 COALESCE](#4.2 COALESCE)

[4.3 NULLIF](#4.3 NULLIF)

[4.4 GREATEST / LEAST](#4.4 GREATEST / LEAST)

[第五章 聚合函数](#第五章 聚合函数)

[5.1 COUNT](#5.1 COUNT)

[5.2 SUM / AVG](#5.2 SUM / AVG)

[5.3 MAX / MIN](#5.3 MAX / MIN)

[5.4 STRING_AGG](#5.4 STRING_AGG)

[5.5 ARRAY_AGG](#5.5 ARRAY_AGG)

[第六章 类型转换函数](#第六章 类型转换函数)

[6.1 CAST 与 :: 操作符](#6.1 CAST 与 :: 操作符)

[6.2 TO_CHAR(数值转换)](#6.2 TO_CHAR(数值转换))

[6.3 TO_NUMBER](#6.3 TO_NUMBER)

[6.4 TO_DATE / TO_TIMESTAMP](#6.4 TO_DATE / TO_TIMESTAMP)


场景设定:本讲义以一家保险公司的数据平台为背景。我们将创建客户、代理人、保单和理赔四张核心表,并基于这些表中的真实业务数据,逐一演示 PostgreSQL 内置函数的使用方法。你可以将本文当做一本"案头速查手册",在编写 SQL 时随时翻阅。

第零章:环境准备:保险业务数据模型

在开始学习函数之前,请在你的 PostgreSQL 数据库中依次执行以下建表和插入数据的脚本。所有后续示例都会基于这些数据。

sql 复制代码
-- 创建Schema
CREATE schema if not exists  policy;

-- =====================================================
-- 0.1 代理人表 (agents)
-- =====================================================

CREATE TABLE policy.agents (
    agent_id    INT PRIMARY KEY,
    agent_name  VARCHAR(50),
    phone       VARCHAR(20),
    hire_date   DATE,
    commission_rate NUMERIC(3,2)   -- 佣金比例,如0.15表示15%
);

INSERT INTO policy.agents VALUES
(1, '张伟', '13800001111', '2018-03-15', 0.12),
(2, '李娜', '13900002222', '2020-07-01', 0.15),
(3, '王强', '13600003333', '2016-01-20', 0.10);

-- =====================================================
-- 0.2 客户表 (customers)
-- =====================================================
CREATE TABLE policy.customers (
    customer_id   INT PRIMARY KEY,
    full_name     VARCHAR(80),
    gender        CHAR(1) CHECK (gender IN ('M','F')),
    birth_date    DATE,
    city          VARCHAR(30),
    agent_id      INT REFERENCES policy.agents(agent_id)  -- 关联的代理人
);

INSERT INTO policy.customers VALUES
(101, '赵晓明', 'M', '1990-05-20', '北京', 1),
(102, '钱丽华', 'F', '1985-12-10', '上海', 1),
(103, '孙志伟', 'M', '1978-08-15', '广州', 2),
(104, '李芳',   'F', '1993-03-22', '深圳', 2),
(105, '周国强', 'M', '2000-11-01', '北京', 3),
(106, '吴敏',   'F', '1968-07-07', '上海', NULL);  -- 线上客户,无专属代理人

-- =====================================================
-- 0.3 保单表 (policies)
-- =====================================================
CREATE TABLE policy.policies (
    policy_id      INT PRIMARY KEY,
    customer_id    INT REFERENCES policy.customers(customer_id),
    product_name   VARCHAR(60),
    premium        NUMERIC(10,2),    -- 年缴保费
    insured_amount NUMERIC(12,2),    -- 保额
    start_date     DATE,
    end_date       DATE,
    status         VARCHAR(20) DEFAULT '有效'  -- 有效/失效/理赔中
);

INSERT INTO policy.policies VALUES
(1001, 101, '乐享一生年金险',     12000.00, 500000.00, '2022-01-01', '2042-01-01', '有效'),
(1002, 101, '百万医疗险',          450.00,  2000000.00,'2023-05-10', '2024-05-09', '有效'),
(1003, 102, '重大疾病险',         8000.00,  300000.00, '2021-09-01', NULL,       '有效'),
(1004, 103, '定期寿险',           1500.00,  1000000.00,'2020-06-15', '2040-06-14', '有效'),
(1005, 104, '百万医疗险',          380.00,  2000000.00,'2024-01-01', '2025-01-01', '有效'),
(1006, 104, '意外伤害险',          200.00,  500000.00, '2023-11-01', '2024-10-31', '有效'),
(1007, 105, '乐享一生年金险',     10000.00, 400000.00, '2022-07-01', '2042-07-01', '有效'),
(1008, 106, '重大疾病险',         6500.00,  200000.00, '2019-03-15', NULL,       '失效');  -- 已停效

-- =====================================================
-- 0.4 理赔表 (claims)
-- =====================================================
CREATE TABLE policy.claims (
    claim_id     INT PRIMARY KEY,
    policy_id    INT REFERENCES policy.policies(policy_id),
    claim_date   DATE,
    claim_amount NUMERIC(10,2),
    claim_status VARCHAR(20) DEFAULT '处理中'   -- 处理中/已结案/拒赔
);

INSERT INTO policy.claims VALUES
(2001, 1002, '2023-12-01', 15000.00, '已结案'),
(2002, 1002, '2024-02-15',  8000.00, '已结案'),
(2003, 1003, '2022-06-10', 50000.00, '已结案'),
(2004, 1005, '2024-07-20', 12000.00, '处理中'),
(2005, 1006, '2024-03-01',  2000.00, '已结案'),
(2006, 1008, '2020-05-18', 35000.00, '拒赔');

输出如下内容:

现在,数据已就绪。让我们正式进入 PostgreSQL 内置函数的世界。

第一章 字符串函数

在保险公司,经常需要处理客户姓名、产品名称、电话号码等文本数据。下面的字符串函数将帮你轻松完成拼接、截取、清洗等工作。

1.1 CONCAT 与 CONCAT_WS

(1) CONCAT

概念 :将多个字符串或字段值拼接成一个字符串。如果参数中有 NULLCONCAT 会将其视为空字符串,继续拼接其余部分,不会导致整个结果为 NULL

语法CONCAT(str1, str2, ..., strN)

业务案例:生成客户的完整称呼(姓名 + 性别),方便在报表中展示。

sql 复制代码
select customer_id
      ,full_name
      ,gender
      ,CONCAT(full_name, ' (', gender, ')') AS display_name
FROM policy.customers;

结果

sql 复制代码
101        赵晓明        M        赵晓明 (M)
102        钱丽华        F        钱丽华 (F)
103        孙志伟        M        孙志伟 (M)
104        李芳          F        李芳 (F)
105        周国强        M        周国强 (M)
106        吴敏          F        吴敏 (F)

(2)CONCAT_WS

概念CONCAT_WS 是 "Concatenate With Separator" 的缩写。它用第一个参数作为分隔符,将后续的字符串连接起来。与 CONCAT 相同,它会自动跳过 NULL 值;但如果分隔符本身是 NULL,则整个函数返回 NULL

语法CONCAT_WS(separator, str1, str2, ...)

业务案例:生成客户的通讯地址,用逗号分隔城市和姓名,即使某部分缺失也不会多出无用的逗号。

sql 复制代码
SELECT 
    customer_id,
    CONCAT_WS(' - ', full_name, city) AS contact
FROM customers;

结果

sql 复制代码
101        赵晓明        北京        赵晓明 - 北京
102        钱丽华        上海        钱丽华 - 上海
103        孙志伟        广州        孙志伟 - 广州
104        李芳          深圳        李芳 - 深圳
105        周国强        北京        周国强 - 北京
106        吴敏          上海        吴敏 - 上海

1.2 SUBSTRING

概念:从源字符串中截取从指定位置开始、指定长度的子串。位置索引从1开始。如果省略长度参数,则截取从起始位置到字符串末尾的所有字符。

语法

  • SUBSTRING(string FROM start [FOR length])

  • SUBSTRING(string, start, length)

业务案例 :从保单号中提取业务标识(假设保单号的第2位到第4位代表产品系列)。例如保单号 1001,我们可以截取 "001" 部分。

sql 复制代码
select policy_id
      ,SUBSTRING(policy_id::text FROM 2 FOR 3) AS product_series
      ,SUBSTRING(policy_id::text,2,3) AS product_series
FROM policy.policies;

输出如下内容:

sql 复制代码
1001        001        001
1002        002        002
1003        003        003
1004        004        004
1005        005        005
1006        006        006
1007        007        007
1008        008        008

1.3 UPPER / LOWER / INITCAP

概念

  • UPPER:将字符串全部转换为大写。

  • LOWER:将字符串全部转换为小写。

  • INITCAP:将每个单词的首字母转换为大写,其余字母转换为小写。单词分隔符包括空格、连字符、下划线等。

语法UPPER(string), LOWER(string), INITCAP(string

业务案例:将客户姓名统一为首字母大写的规范格式,用于标准信函。

sql 复制代码
SELECT
    full_name,
    INITCAP(full_name) AS standardized_name
FROM policy.customers;

如果数据库中已存有英文名,INITCAP('john doe') 会返回 'John Doe'

sql 复制代码
-- 将产品名称转换为全大写,用于报表标题
SELECT 
    product_name,
    UPPER(product_name) AS product_label
FROM policy.policies;

1.4 LENGTH

概念 :返回字符串中的字符个数(而不是字节数)。如果字符串为 NULL 则返回 NULL,空字符串返回 0

语法LENGTH(string)

业务案例:检查客户手机号的长度是否正确(应为11位)。

sql 复制代码
SELECT
    full_name,
    phone,
    LENGTH(phone) AS phone_length
FROM policy.agents;

结果:

sql 复制代码
full_name | phone       | phone_length
----------+-------------+-------------
张伟      | 13800001111 |          11
李娜      | 13900002222 |          11
王强      | 13600003333 |          11

1.5 TRIM(及 LTRIM / RTRIM)

概念:移除字符串首尾(或指定侧)的指定字符,默认移除空格。这是清洗输入数据时最常用的函数。

语法

  • TRIM([LEADING | TRAILING | BOTH] [char] FROM string)

  • LTRIM(string [, char]):仅去除左侧字符

  • RTRIM(string [, char]):仅去除右侧字符

业务案例:某次数据导入后,客户姓名前后意外包含了空格和制表符,需要清洗。

sql 复制代码
SELECT TRIM(BOTH ' ' FROM ' 赵晓明 ') AS cleaned_name;   -- 结果为 '赵晓明'

若要清除字段前后所有空白符(包括空格和制表符),可以直接使用 TRIM(string)

sql 复制代码
-- 假设导入的保单状态字段含有前导空格
UPDATE policies SET status = TRIM(status);

1.6 REPLACE

概念:将字符串中出现的所有指定子串替换成另一个子串。如果未找到匹配的子串,则返回原字符串。

语法REPLACE(string, old_substring, new_substring)

业务案例:将产品名称中的"险"字统一替换为"(保险)",以适应某些报表系统的命名要求。

sql 复制代码
SELECT
    product_name,
    REPLACE(product_name, '险', '(保险)') AS formatted_name
FROM policy.policies;

1.7 POSITION / STRPOS

概念 :返回子串在字符串中第一次出现的位置(从1开始计数)。如果未找到则返回 0

语法

  • POSITION(substring IN string)

  • STRPOS(string, substring)

业务案例 :快速定位保单号中连字符 - 的位置,以便后续拆分。

sql 复制代码
SELECT
    policy_id::TEXT,
    POSITION('1' IN policy_id::TEXT) AS pos
FROM policy.policies;

1.8 LEFT / RIGHT

概念:分别从字符串左端或右端截取指定数量的字符。

语法LEFT(string, n), RIGHT(string, n)

业务案例:提取代理人手机号的前三位(运营商号段)和后四位。

sql 复制代码
SELECT
    agent_name,
    LEFT(phone, 3) AS prefix,
    RIGHT(phone, 4) AS suffix
FROM policy.agents;

1.9 正则表达式函数

1.9.1 REGEXP_MATCHES

概念:返回字符串中第一个匹配正则表达式的子串。结果以集合(set)的形式返回(通常为单行单列),可用于校验数据格式。

语法REGEXP_MATCHES(string, pattern [, flags])

业务案例 :校验客户手机号是否为11位数字。注意在正则表达式中 \d 需要写成 \\d

sql 复制代码
SELECT
    phone,
    (REGEXP_MATCHES(phone, '^\\d{11}$'))[1] IS NOT NULL AS is_valid
FROM policy.agents;
1.9.2 REGEXP_REPLACE

概念:用正则表达式匹配并替换字符串中的内容。

语法REGEXP_REPLACE(string, pattern, replacement [, flags])

业务案例 :将保单号中的数字替换为星号,实现脱敏展示(如 1001****)。

sql 复制代码
SELECT
    policy_id::TEXT,
    REGEXP_REPLACE(policy_id::TEXT, '[0-9]', '*', 'g') AS masked_id
FROM policy.policies;

第二章 数值函数

保费计算、佣金比例、保额统计......在保险行业,数值运算无处不在。PostgreSQL 提供了精确的数值函数,避免因浮点数误差导致财务偏差。

2.1 ROUND

概念:对数值进行四舍五入,保留指定小数位数。当第二个参数为负数时,会在整数位上进行四舍五入。

语法ROUND(numeric_value, decimal_places)

业务案例:将代理人的佣金比例四舍五入保留一位小数,或将保额向上舍入到千元。

sql 复制代码
SELECT
    agent_name,
    commission_rate,
    ROUND(commission_rate, 1) AS rounded_rate
FROM policy.agents;

-- 保额四舍五入到千元
SELECT
    policy_id,
    insured_amount,
    ROUND(insured_amount, -3) AS rounded_amount
FROM policy.policies;

2.2 TRUNC

概念:截断数值到指定位数,直接舍弃多余的小数位,不进行四舍五入。

语法TRUNC(numeric_value, decimal_places)

业务案例:计算代理人年终奖时,按整百元向下取整发放。

sql 复制代码
SELECT
    agent_name,
    commission_rate * 100000 AS bonus_base,
    TRUNC(commission_rate * 100000, -2) AS bonus_rounded_down
FROM policy.agents;

2.3 CEIL / FLOOR

概念CEIL 返回不小于参数的最小整数(向上取整),FLOOR 返回不大于参数的最大整数(向下取整)。

语法CEIL(numeric_value), FLOOR(numeric_value)

业务案例:计算一个客户的所有保单总保费后,向上取整作为年度预算参考。

sql 复制代码
SELECT
    customer_id,
    SUM(premium) AS total_premium,
    CEIL(SUM(premium)) AS budget_ceiling,
    FLOOR(SUM(premium)) AS budget_floor
FROM policy.policies
WHERE status = '有效'
GROUP BY customer_id;

2.4 MOD

概念:返回除法运算的余数。可用于判断奇偶、分组等场景。

语法MOD(dividend, divisor)

业务案例:将客户按 ID 的奇偶性分组,用于 AB 测试或批量任务分割。

sql 复制代码
SELECT
    customer_id,
    full_name,
    CASE WHEN MOD(customer_id, 2) = 0 THEN '偶数' ELSE '奇数' END AS group_id
FROM policy.customers;

2.5 ABS

概念:返回数值的绝对值。

语法ABS(numeric_value)

业务案例:计算实际理赔金额与预估金额的偏差绝对值。

sql 复制代码
SELECT
    claim_id,
    claim_amount,
    ABS(claim_amount - 10000) AS deviation_from_10k
FROM policy.claims;

2.6 POWER / SQRT

概念POWER(m, n) 返回 m 的 n 次方;SQRT(x) 返回 x 的平方根。

语法POWER(base, exponent), SQRT(numeric_value)

业务案例 :在保费厘定精算模型中,经常需要计算平方和、标准差等,SQRT 就是基础工具。

sql 复制代码
SELECT
    SQRT(AVG(premium * premium)) AS rms_premium
FROM policies;

2.7 RANDOM

概念:返回介于 0.0(包含)和 1.0(不包含)之间的随机浮点数。

语法RANDOM()

业务案例:从客户库中随机抽取 5% 的客户进行满意度调查。

sql 复制代码
SELECT *
FROM policy.customers
WHERE RANDOM() < 0.05;

第三章 日期/时间函数

保险合同的关键就是时间------起保日期、理赔日期、续保提醒......日期函数是保险数据工程师的"基本功"。

3.1 CURRENT_DATE / CURRENT_TIMESTAMP / NOW

概念CURRENT_DATE 返回当前日期;CURRENT_TIMESTAMP 返回当前时间戳(含时区);NOW()CURRENT_TIMESTAMP 等价。

语法:无需参数。

业务案例:查询所有已过终止日期的保单(失效)。

sql 复制代码
SELECT *
FROM policy.policies
WHERE end_date IS NOT NULL
  AND end_date < CURRENT_DATE;

3.2 EXTRACT / DATE_PART

概念 :从日期/时间中提取特定的部分,如年、月、日、小时等。EXTRACTDATE_PART 功能几乎相同,只是书写风格略有差异。

语法

  • EXTRACT(field FROM source)

  • DATE_PART('field', source)

业务案例:分析保单生效日期的月份分布,了解哪个月份是销售高峰期。

sql 复制代码
SELECT
    EXTRACT(MONTH FROM start_date) AS month_start,
    COUNT(*) AS policy_count
FROM policy.policies
GROUP BY EXTRACT(MONTH FROM start_date)
ORDER BY month_start;

3.3 AGE

概念 :计算两个日期之间的间隔,返回 interval 类型(人类可读的"X年X月X天")。若只给一个参数,则计算该日期到当前日期之间的间隔。

语法

  • AGE(timestamp1, timestamp2)

  • AGE(timestamp)

业务案例:计算每个客户的年龄(基于出生日期)。

sql 复制代码
SELECT
    full_name,
    birth_date,
    AGE(CURRENT_DATE, birth_date) AS current_age
FROM policy.customers;

3.4 DATE_TRUNC

概念:将日期/时间截断到指定的精度,例如截断到月份,则返回该月第一天。

语法DATE_TRUNC(precision, source)

业务案例:按月份统计理赔总额,需要将所有理赔日期归一化到所在月份。

sql 复制代码
SELECT
    DATE_TRUNC('month', claim_date) AS claim_month,
    SUM(claim_amount) AS total_claim
FROM policy.claims
WHERE claim_status = '已结案'
GROUP BY DATE_TRUNC('month', claim_date)
ORDER BY claim_month;

3.5 TO_CHAR(日期格式化)

概念:将日期/时间按照指定的格式模式转换为字符串,是生成报表、导出数据时的利器。

语法TO_CHAR(timestamp, format_pattern)

常见格式符

  • YYYY:四位年份

  • MM:月份(01-12)

  • DD:日(01-31)

  • HH24:小时(24小时制)

  • MI:分钟

  • SS:秒

  • Day:星期名称

  • Q:季度

业务案例:将保单起保日期格式化为"2022年01月01日"的形式。

sql 复制代码
SELECT
    policy_id,
    start_date,
    TO_CHAR(start_date, 'YYYY"年"MM"月"DD"日"') AS formatted_start
FROM policy.policies;

第四章 条件判断函数

在数据处理中,经常需要根据不同的条件返回不同的值,比如给保单打标签、处理缺失值、避免除零错误等。

4.1 CASE WHEN

概念 :SQL 中的条件表达式,可以实现复杂的逻辑分支。有两种形式:搜索式 CASE(最常用)和简单 CASE

语法

sql 复制代码
CASE
  WHEN condition1 THEN result1
  WHEN condition2 THEN result2
  ...
  [ELSE default_result]
END

业务案例:根据年缴保费将保单划分为"高端""中端""经济型"三类。

sql 复制代码
SELECT
    policy_id,
    premium,
    CASE
        WHEN premium >= 8000 THEN '高端'
        WHEN premium >= 1000 THEN '中端'
        ELSE '经济型'
    END AS tier
FROM policy.policies;

4.2 COALESCE

概念 :返回参数列表中第一个非 NULL 的值。是处理缺失数据的首选工具。

语法COALESCE(value1, value2, ..., valueN)

业务案例customers 表中 agent_id 可能为 NULL(线上客户),我们希望未绑定代理人的客户在报表中显示为"无专属代理人"。

sql 复制代码
SELECT
    full_name,
    COALESCE(agent_id::TEXT, '无专属代理人') AS agent_display
FROM customers;

4.3 NULLIF

概念 :如果两个参数相等,则返回 NULL;否则返回第一个参数的值。通常用于规避除零错误。

语法NULLIF(value1, value2)

业务案例 :计算理赔通过率时,分母(申请理赔次数)可能为零,使用 NULLIF 避免除以零报错。

sql 复制代码
SELECT
    COUNT(*) AS total_claims,
    SUM(CASE WHEN claim_status = '已结案' THEN 1 ELSE 0 END) AS settled,
    SUM(CASE WHEN claim_status = '已结案' THEN 1 ELSE 0 END) * 1.0
        / NULLIF(COUNT(*), 0) AS settlement_rate
FROM claims;

4.4 GREATEST / LEAST

概念 :分别返回列表中的最大值或最小值。注意:参数中的 NULL 会导致整个函数返回 NULL,除非所有参数都是 NULL

语法GREATEST(value1, value2, ...), LEAST(value1, value2, ...)

业务案例:计算客户所有有效保单中最高的保额和最低的年缴保费。

sql 复制代码
SELECT
    customer_id,
    MAX(insured_amount) AS max_cover,
    MIN(premium) AS min_premium
FROM policy.policies
WHERE status = '有效'
GROUP BY customer_id;

虽然 MAX/MIN 是聚合函数,但 GREATEST 可用于单行多列的比较,例如比较多个年度保费调整方案,选择最高者:

sql 复制代码
SELECT
    policy_id,
    GREATEST(premium * 1.05, premium * 1.10, premium * 1.15) AS max_next_year_premium
FROM policy.policies;

第五章 聚合函数

聚合函数将多行数据汇总为单个值,通常与 GROUP BY 结合使用,是数据分析的基石。

5.1 COUNT

概念 :计数函数。COUNT(*) 计算所有行的数量(包括 NULL 行);COUNT(column) 计算该列非 NULL 值的数量;COUNT(DISTINCT column) 计算去重后的非 NULL 值数量。

语法COUNT( [DISTINCT] expression )

业务案例

  • 统计客户总数

  • 统计有多少个客户购买了"百万医疗险"

sql 复制代码
-- 全部客户数(包括所有行)
SELECT COUNT(*) AS total_customers FROM policy.customers;

-- 购买了百万医疗险的客户数(去重)
SELECT COUNT(DISTINCT customer_id) AS med_cust_count
FROM policy.policies
WHERE product_name = '百万医疗险';

5.2 SUM / AVG

概念 :对数值列求和或计算平均值。它们自动忽略 NULL 值。

语法SUM(column), AVG(column)

业务案例:计算公司总保费收入,以及每单平均保费。

sql 复制代码
SELECT
    SUM(premium) AS total_premium,
    AVG(premium) AS avg_premium
FROM policy.policies
WHERE status = '有效';

5.3 MAX / MIN

概念:返回列中的最大值或最小值。可用于日期、字符串和数值类型。

语法MAX(column), MIN(column)

业务案例:找出最老的保单(最早起保日期)和最近生效的保单。

sql 复制代码
SELECT
    MIN(start_date) AS oldest_policy_start,
    MAX(start_date) AS newest_policy_start
FROM policy.policies;

5.4 STRING_AGG

概念 :将组内多行的字符串拼接成一个字符串,可指定分隔符并可选择排序顺序。类似 MySQL 的 GROUP_CONCAT

语法STRING_AGG(expression, delimiter [ORDER BY ...])

业务案例:为每位代理人列出其名下的所有客户姓名,用顿号分隔。

sql 复制代码
SELECT
    a.agent_name,
    STRING_AGG(c.full_name, '、' ORDER BY c.customer_id) AS client_list
FROM policy.agents a
INNER JOIN policy.customers c 
        ON a.agent_id = c.agent_id
GROUP BY a.agent_name;

5.5 ARRAY_AGG

概念:将组内多行的值聚合成一个 PostgreSQL 数组。非常适合传递给应用程序或进行二次分析。

语法ARRAY_AGG(expression [ORDER BY ...])

业务案例:将每个客户持有的所有保单 ID 收集到一个数组中。

sql 复制代码
SELECT
    customer_id,
    ARRAY_AGG(policy_id ORDER BY start_date) AS policy_list
FROM policy.policies
GROUP BY customer_id;

第六章 类型转换函数

数据类型不匹配是 SQL 开发中的常见问题。PostgreSQL 提供了灵活的类型转换工具,确保数据能被正确解释和计算。

6.1 CAST 与 :: 操作符

概念 :将一种数据类型显式转换为另一种。:: 是 PostgreSQL 特有的快捷写法。

语法

  • CAST(expression AS target_type)

  • expression::target_type

业务案例 :将理赔金额转换为整数进行财务入账,或将字符串形式的日期转换为真正的 DATE 类型。

sql 复制代码
-- 理赔金额转为整数
SELECT claim_id, CAST(claim_amount AS INTEGER) FROM claims;

-- 使用 :: 快捷方式
SELECT '2025-06-01'::DATE + INTERVAL '1 month';

6.2 TO_CHAR(数值转换)

概念:将数值按照指定的格式掩码转换为字符串,常用于财务报表的输出。

语法TO_CHAR(numeric_value, format_pattern)

常用格式符

  • 9:数字位(不强制显示)

  • 0:数字位(强制显示,不足补零)

  • ,:千分位分隔符

  • L:本地货币符号

  • FM:去除前导空格或尾部零

业务案例:将保额格式化为带有千分位和货币符号的字符串。

sql 复制代码
SELECT
    policy_id,
    insured_amount,
    TO_CHAR(insured_amount, 'FM¥999,999,999.00') AS formatted_amount
FROM policy.policies;

6.3 TO_NUMBER

概念:将格式化的字符串解析成数值。需要格式掩码与字符串严格匹配。

语法TO_NUMBER(string, format_pattern)

业务案例 :导入外部数据时,保费可能以"¥12,345.67"的形式存储,需要转换成可计算的 NUMERIC 类型。

sql 复制代码
SELECT TO_NUMBER('¥12,345.67', 'L99,999.99');

6.4 TO_DATE / TO_TIMESTAMP

概念:将字符串按指定的日期/时间格式转换为对应的日期或时间戳类型。

语法

  • TO_DATE(string, format_pattern)

  • TO_TIMESTAMP(string, format_pattern)

业务案例 :将非标准格式的出生日期字符串(例如 '1990-05-20''20/05/1990')转换为标准日期类型,以便参与日期计算。

sql 复制代码
SELECT TO_DATE('20/05/1990', 'DD/MM/YYYY') AS birth_date;

在我们的 customers 表中,birth_date 已经是 DATE 类型,但在 ETL 过程中经常会用到这两个函数。

结语:以上六大类函数覆盖了保险数据开发中最常用的场景。建议将本文收藏,在实际编写 SQL 时参照示例快速上手。随着 PostgreSQL 版本更新,还会有更多强大的内置函数涌现,但掌握这些基础,你已经可以应对 90% 的数据处理需求。

相关推荐
智者知已应修善业1 小时前
【51单片机8位数码管动态显示日期小数点风格】2023-11-13
c++·经验分享·笔记·算法·51单片机
智者知已应修善业1 小时前
【51单片机有三个LED 分别第一个灯闪三下 再到第二个灯又闪三下 再到第三个灯又闪三下 就这样循环程序】2023-11-16
c++·经验分享·笔记·算法·51单片机
无忧智库1 小时前
电力行业集团数字化转型信息化战略规划方案(PPT)
大数据·人工智能
这是谁的博客?2 小时前
Mamba 状态空间模型深度解析:挑战 Transformer 的新一代架构
深度学习·ai·架构·transformer·ssm·mamba·状态空间模型
苏渡苇2 小时前
Spring Cloud Alibaba:将 Sentinel 熔断限流规则持久化到 Nacos 配置中心
数据库·spring boot·mysql·spring cloud·nacos·sentinel·持久化
杨云龙UP2 小时前
Oracle Recycle Bin 回收站详解:DROP TABLE 后还能找回吗?
linux·运维·数据库·sql·mysql·oracle
笨蛋©2 小时前
[实战] 2026年工程图纸数字化技术指南:GD&T识别与检验计划自动化
ai·数字化·质量管理·制造业·fai
未来之窗软件服务2 小时前
酒店门锁V10SDK接口VB-幽冥大陆(一百26)—东方仙盟
数据库·酒店门锁·仙盟创梦ide·东方仙盟·东方仙盟sdk·东方仙盟幽冥大陆
无忧智库3 小时前
基于5G-A(通感一体)技术的城市低空飞行器实时航线监控底座建设方案(WORD)
大数据·人工智能·5g