Oracle高级函数 #

一、字符串函数 #

1.1 常用字符串函数 #

sql
-- 字符串长度
SELECT LENGTH('Oracle') FROM DUAL;           -- 6
SELECT LENGTH('甲骨文') FROM DUAL;            -- 3
SELECT LENGTHB('甲骨文') FROM DUAL;           -- 6(字节数)

-- 字符串转换
SELECT UPPER('oracle') FROM DUAL;            -- ORACLE
SELECT LOWER('ORACLE') FROM DUAL;            -- oracle
SELECT INITCAP('oracle database') FROM DUAL; -- Oracle Database

-- 字符串截取
SELECT SUBSTR('Oracle', 1, 3) FROM DUAL;     -- Ora
SELECT SUBSTR('Oracle', -3) FROM DUAL;       -- cle
SELECT SUBSTRB('甲骨文', 1, 2) FROM DUAL;    -- 甲(按字节)

-- 字符串查找
SELECT INSTR('Oracle', 'a') FROM DUAL;       -- 3
SELECT INSTR('Oracle', 'a', 1, 1) FROM DUAL; -- 3(从第1位开始,第1次出现)
SELECT INSTR('Oracle', 'a', -1) FROM DUAL;   -- 3(从后往前找)

1.2 字符串处理 #

sql
-- 字符串替换
SELECT REPLACE('Oracle Database', 'Oracle', 'MySQL') FROM DUAL; -- MySQL Database
SELECT REPLACE('Oracle', 'a', 'A') FROM DUAL;                    -- OrAcle

-- 字符串填充
SELECT LPAD('Oracle', 10, '*') FROM DUAL;   -- ****Oracle
SELECT RPAD('Oracle', 10, '*') FROM DUAL;   -- Oracle****

-- 字符串修剪
SELECT TRIM('  Oracle  ') FROM DUAL;        -- Oracle
SELECT LTRIM('  Oracle  ') FROM DUAL;       -- Oracle  
SELECT RTRIM('  Oracle  ') FROM DUAL;       --   Oracle
SELECT TRIM('O' FROM 'Oracle') FROM DUAL;   -- racle

-- 字符串连接
SELECT CONCAT('Hello', ' ', 'World') FROM DUAL; -- Hello World
SELECT 'Hello' || ' ' || 'World' FROM DUAL;     -- Hello World

1.3 正则表达式函数 #

sql
-- REGEXP_LIKE:正则匹配
SELECT * FROM employees
WHERE REGEXP_LIKE(email, '^[a-z]+@[a-z]+\.[a-z]+$');

-- REGEXP_SUBSTR:正则提取
SELECT REGEXP_SUBSTR('Oracle 12c Database', '[0-9]+') FROM DUAL; -- 12

-- REGEXP_INSTR:正则查找位置
SELECT REGEXP_INSTR('Oracle 12c', '[0-9]') FROM DUAL; -- 8

-- REGEXP_REPLACE:正则替换
SELECT REGEXP_REPLACE('Oracle 12c', '[0-9]+', '19c') FROM DUAL; -- Oracle 19c

-- REGEXP_COUNT:正则计数
SELECT REGEXP_COUNT('Oracle 12c 19c', '[0-9]+') FROM DUAL; -- 2

-- 复杂正则示例
-- 提取邮箱
SELECT REGEXP_SUBSTR(
    'Contact: john@example.com or jane@test.org',
    '[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}'
) FROM DUAL;

-- 提取手机号
SELECT REGEXP_SUBSTR(
    'Phone: 138-1234-5678',
    '[0-9]{3}-[0-9]{4}-[0-9]{4}'
) FROM DUAL;

二、日期函数 #

2.1 当前日期时间 #

sql
-- 当前日期时间
SELECT SYSDATE FROM DUAL;                    -- 当前日期
SELECT SYSTIMESTAMP FROM DUAL;               -- 当前时间戳
SELECT CURRENT_DATE FROM DUAL;               -- 会话日期
SELECT CURRENT_TIMESTAMP FROM DUAL;          -- 会话时间戳

-- 时区相关
SELECT DBTIMEZONE FROM DUAL;                 -- 数据库时区
SELECT SESSIONTIMEZONE FROM DUAL;            -- 会话时区
SELECT SYSTIMESTAMP AT TIME ZONE 'UTC' FROM DUAL;  -- UTC时间

2.2 日期计算 #

sql
-- 日期加减
SELECT SYSDATE + 1 FROM DUAL;                -- 加1天
SELECT SYSDATE - 1 FROM DUAL;                -- 减1天
SELECT SYSDATE + 1/24 FROM DUAL;             -- 加1小时
SELECT SYSDATE + 1/1440 FROM DUAL;           -- 加1分钟
SELECT SYSDATE + 1/86400 FROM DUAL;          -- 加1秒

-- ADD_MONTHS函数
SELECT ADD_MONTHS(SYSDATE, 1) FROM DUAL;     -- 加1个月
SELECT ADD_MONTHS(SYSDATE, -1) FROM DUAL;    -- 减1个月

-- MONTHS_BETWEEN函数
SELECT MONTHS_BETWEEN(
    TO_DATE('2024-12-31', 'YYYY-MM-DD'),
    TO_DATE('2024-01-01', 'YYYY-MM-DD')
) FROM DUAL;  -- 11.9677...

-- LAST_DAY函数
SELECT LAST_DAY(SYSDATE) FROM DUAL;          -- 本月最后一天

-- NEXT_DAY函数
SELECT NEXT_DAY(SYSDATE, 'MONDAY') FROM DUAL; -- 下一个周一
SELECT NEXT_DAY(SYSDATE, 2) FROM DUAL;        -- 下一个周一(2=周一)

2.3 日期截取和舍入 #

sql
-- TRUNC:日期截取
SELECT TRUNC(SYSDATE) FROM DUAL;             -- 截取到天(去掉时间)
SELECT TRUNC(SYSDATE, 'YYYY') FROM DUAL;     -- 截取到年(年初)
SELECT TRUNC(SYSDATE, 'MM') FROM DUAL;       -- 截取到月(月初)
SELECT TRUNC(SYSDATE, 'DD') FROM DUAL;       -- 截取到天
SELECT TRUNC(SYSDATE, 'DAY') FROM DUAL;      -- 截取到周(周日)
SELECT TRUNC(SYSDATE, 'HH24') FROM DUAL;     -- 截取到小时
SELECT TRUNC(SYSDATE, 'MI') FROM DUAL;       -- 截取到分钟

-- ROUND:日期舍入
SELECT ROUND(SYSDATE) FROM DUAL;             -- 舍入到天
SELECT ROUND(SYSDATE, 'YYYY') FROM DUAL;     -- 舍入到年
SELECT ROUND(SYSDATE, 'MM') FROM DUAL;       -- 舍入到月

2.4 日期提取 #

sql
-- EXTRACT函数
SELECT EXTRACT(YEAR FROM SYSDATE) FROM DUAL;    -- 年
SELECT EXTRACT(MONTH FROM SYSDATE) FROM DUAL;   -- 月
SELECT EXTRACT(DAY FROM SYSDATE) FROM DUAL;     -- 日
SELECT EXTRACT(HOUR FROM SYSTIMESTAMP) FROM DUAL;  -- 时
SELECT EXTRACT(MINUTE FROM SYSTIMESTAMP) FROM DUAL; -- 分
SELECT EXTRACT(SECOND FROM SYSTIMESTAMP) FROM DUAL; -- 秒

-- 日期相关函数
SELECT TO_CHAR(SYSDATE, 'YYYY') AS year FROM DUAL;
SELECT TO_CHAR(SYSDATE, 'MM') AS month FROM DUAL;
SELECT TO_CHAR(SYSDATE, 'DD') AS day FROM DUAL;
SELECT TO_CHAR(SYSDATE, 'DAY') AS weekday FROM DUAL;
SELECT TO_CHAR(SYSDATE, 'D') AS weekday_num FROM DUAL;  -- 1-7
SELECT TO_CHAR(SYSDATE, 'WW') AS week FROM DUAL;        -- 年中周数
SELECT TO_CHAR(SYSDATE, 'Q') AS quarter FROM DUAL;      -- 季度

三、转换函数 #

3.1 TO_CHAR #

sql
-- 数字转字符串
SELECT TO_CHAR(12345.67, '999,999.99') FROM DUAL;    -- 12,345.67
SELECT TO_CHAR(12345.67, '$99,999.99') FROM DUAL;     -- $12,345.67
SELECT TO_CHAR(12345.67, 'L99,999.99') FROM DUAL;     -- ¥12,345.67
SELECT TO_CHAR(0.1234, '0.9999') FROM DUAL;           -- 0.1234
SELECT TO_CHAR(123, '00000') FROM DUAL;               -- 00123

-- 日期转字符串
SELECT TO_CHAR(SYSDATE, 'YYYY-MM-DD') FROM DUAL;
SELECT TO_CHAR(SYSDATE, 'YYYY-MM-DD HH24:MI:SS') FROM DUAL;
SELECT TO_CHAR(SYSDATE, 'YYYY"年"MM"月"DD"日"') FROM DUAL;
SELECT TO_CHAR(SYSDATE, 'DAY, DD MONTH YYYY') FROM DUAL;
SELECT TO_CHAR(SYSDATE, 'YYYY-MM-DD HH24:MI:SS AM') FROM DUAL;

-- 常用日期格式
-- YYYY:四位年
-- YY:两位年
-- MM:两位月
-- MON:月份缩写
-- MONTH:月份全称
-- DD:日
-- DAY:星期
-- HH24:24小时制
-- HH12:12小时制
-- MI:分钟
-- SS:秒
-- AM/PM:上午/下午

3.2 TO_DATE #

sql
-- 字符串转日期
SELECT TO_DATE('2024-01-15', 'YYYY-MM-DD') FROM DUAL;
SELECT TO_DATE('2024/01/15', 'YYYY/MM/DD') FROM DUAL;
SELECT TO_DATE('15-01-2024', 'DD-MM-YYYY') FROM DUAL;
SELECT TO_DATE('2024-01-15 10:30:00', 'YYYY-MM-DD HH24:MI:SS') FROM DUAL;
SELECT TO_DATE('January 15, 2024', 'MONTH DD, YYYY') FROM DUAL;

-- 使用DATE字面量
SELECT DATE '2024-01-15' FROM DUAL;

-- 使用TIMESTAMP字面量
SELECT TIMESTAMP '2024-01-15 10:30:00' FROM DUAL;

3.3 TO_NUMBER #

sql
-- 字符串转数字
SELECT TO_NUMBER('12345') FROM DUAL;
SELECT TO_NUMBER('12,345.67', '99,999.99') FROM DUAL;
SELECT TO_NUMBER('$12,345.67', '$99,999.99') FROM DUAL;

-- 使用CAST
SELECT CAST('12345' AS NUMBER) FROM DUAL;
SELECT CAST('123.45' AS NUMBER(10,2)) FROM DUAL;

3.4 CAST函数 #

sql
-- CAST通用转换
SELECT CAST(123 AS VARCHAR2(10)) FROM DUAL;        -- 数字转字符串
SELECT CAST('123' AS NUMBER) FROM DUAL;            -- 字符串转数字
SELECT CAST(SYSDATE AS TIMESTAMP) FROM DUAL;       -- 日期转时间戳
SELECT CAST(SYSTIMESTAMP AS DATE) FROM DUAL;       -- 时间戳转日期

-- CAST与TO_CHAR比较
SELECT CAST(12345.67 AS VARCHAR2(20)) FROM DUAL;   -- 12345.67
SELECT TO_CHAR(12345.67, '99999.99') FROM DUAL;    -- 12345.67

四、条件函数 #

4.1 NVL函数 #

sql
-- NVL:NULL值替换
SELECT NVL(NULL, 0) FROM DUAL;                    -- 0
SELECT NVL(NULL, 'N/A') FROM DUAL;                -- N/A

-- 使用示例
SELECT 
    employee_id,
    first_name,
    salary,
    NVL(commission_pct, 0) AS commission,
    salary + salary * NVL(commission_pct, 0) AS total_income
FROM employees;

4.2 NVL2函数 #

sql
-- NVL2:根据是否为NULL返回不同值
-- NVL2(expr1, expr2, expr3)
-- 如果expr1不为NULL,返回expr2
-- 如果expr1为NULL,返回expr3

SELECT NVL2(NULL, 'NOT NULL', 'NULL') FROM DUAL;   -- NULL
SELECT NVL2('Value', 'NOT NULL', 'NULL') FROM DUAL; -- NOT NULL

-- 使用示例
SELECT 
    employee_id,
    first_name,
    NVL2(commission_pct, '有提成', '无提成') AS has_commission
FROM employees;

4.3 NULLIF函数 #

sql
-- NULLIF:如果相等返回NULL
-- NULLIF(expr1, expr2)
-- 如果expr1 = expr2,返回NULL
-- 否则返回expr1

SELECT NULLIF(10, 10) FROM DUAL;                   -- NULL
SELECT NULLIF(10, 20) FROM DUAL;                   -- 10

-- 使用示例:避免除零错误
SELECT 
    employee_id,
    salary,
    commission_pct,
    NULLIF(commission_pct, 0) AS safe_commission
FROM employees;

4.4 COALESCE函数 #

sql
-- COALESCE:返回第一个非NULL值
SELECT COALESCE(NULL, NULL, 'Value') FROM DUAL;    -- Value
SELECT COALESCE(NULL, 'Second', 'Third') FROM DUAL; -- Second

-- 使用示例
SELECT 
    employee_id,
    COALESCE(phone_number, mobile_number, email) AS contact
FROM employees;

4.5 CASE表达式 #

sql
-- 简单CASE表达式
SELECT 
    employee_id,
    first_name,
    department_id,
    CASE department_id
        WHEN 10 THEN 'IT'
        WHEN 20 THEN 'Sales'
        WHEN 30 THEN 'HR'
        ELSE 'Other'
    END AS department_name
FROM employees;

-- 搜索CASE表达式
SELECT 
    employee_id,
    first_name,
    salary,
    CASE 
        WHEN salary >= 10000 THEN 'High'
        WHEN salary >= 7000 THEN 'Medium'
        WHEN salary >= 5000 THEN 'Low'
        ELSE 'Very Low'
    END AS salary_level
FROM employees;

-- 在ORDER BY中使用CASE
SELECT employee_id, first_name, salary
FROM employees
ORDER BY CASE 
    WHEN department_id = 10 THEN 1
    WHEN department_id = 20 THEN 2
    ELSE 3
END;

4.6 DECODE函数 #

sql
-- DECODE:Oracle特有的条件函数
SELECT 
    employee_id,
    first_name,
    DECODE(department_id,
        10, 'IT',
        20, 'Sales',
        30, 'HR',
        'Other'
    ) AS department_name
FROM employees;

-- DECODE嵌套
SELECT 
    employee_id,
    first_name,
    DECODE(department_id,
        10, DECODE(job_id, 'IT_PROG', 'Programmer', 'IT Staff'),
        20, 'Sales',
        'Other'
    ) AS job_title
FROM employees;

-- DECODE实现范围判断
SELECT 
    employee_id,
    salary,
    DECODE(SIGN(salary - 10000),
        1, 'High',
        0, 'High',
        -1, DECODE(SIGN(salary - 5000),
            1, 'Medium',
            0, 'Medium',
            -1, 'Low'
        )
    ) AS salary_level
FROM employees;

五、聚合函数扩展 #

5.1 LISTAGG函数 #

sql
-- LISTAGG:字符串聚合
SELECT 
    department_id,
    LISTAGG(first_name, ',') WITHIN GROUP (ORDER BY first_name) AS employees
FROM employees
GROUP BY department_id;

-- 结果
DEPARTMENT_ID EMPLOYEES
------------- -----------------
           10 Jane,John
           20 Alice,Bob
           30 Charlie

-- 处理超长字符串(12c R2+)
SELECT 
    department_id,
    LISTAGG(first_name, ',' ON OVERFLOW TRUNCATE '...' WITH COUNT) 
        WITHIN GROUP (ORDER BY first_name) AS employees
FROM employees
GROUP BY department_id;

5.2 统计函数 #

sql
-- VARIANCE:方差
SELECT VARIANCE(salary) FROM employees;

-- STDDEV:标准差
SELECT STDDEV(salary) FROM employees;

-- MEDIAN:中位数
SELECT MEDIAN(salary) FROM employees;

-- PERCENTILE_CONT:百分位数
SELECT PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY salary) FROM employees;

-- PERCENTILE_DISC:离散百分位数
SELECT PERCENTILE_DISC(0.5) WITHIN GROUP (ORDER BY salary) FROM employees;

-- PERCENT_RANK:百分比排名
SELECT 
    employee_id,
    salary,
    PERCENT_RANK() OVER (ORDER BY salary) AS pct_rank
FROM employees;

六、其他实用函数 #

6.1 数值函数 #

sql
-- 四舍五入
SELECT ROUND(123.456, 2) FROM DUAL;        -- 123.46
SELECT ROUND(123.456, -1) FROM DUAL;       -- 120

-- 截断
SELECT TRUNC(123.456, 2) FROM DUAL;        -- 123.45
SELECT TRUNC(123.456, -1) FROM DUAL;       -- 120

-- 取模
SELECT MOD(10, 3) FROM DUAL;               -- 1

-- 绝对值
SELECT ABS(-123) FROM DUAL;                -- 123

-- 幂运算
SELECT POWER(2, 10) FROM DUAL;             -- 1024

-- 平方根
SELECT SQRT(16) FROM DUAL;                 -- 4

-- 符号
SELECT SIGN(-10) FROM DUAL;                -- -1
SELECT SIGN(10) FROM DUAL;                 -- 1
SELECT SIGN(0) FROM DUAL;                  -- 0

-- 向上/向下取整
SELECT CEIL(123.1) FROM DUAL;              -- 124
SELECT FLOOR(123.9) FROM DUAL;             -- 123

6.2 空值处理函数 #

sql
-- LNNVL:条件取反(包含NULL)
SELECT * FROM employees
WHERE LNNVL(salary > 10000);
-- 返回salary <= 10000或salary为NULL的行

-- NANVL:处理NaN
SELECT NANVL(commission_pct, 0) FROM employees;

-- NULLIF与COALESCE组合
SELECT COALESCE(NULLIF(a, b), c) FROM table;

6.3 系统函数 #

sql
-- 用户信息
SELECT USER FROM DUAL;                     -- 当前用户
SELECT UID FROM DUAL;                      -- 用户ID
SELECT USERENV('SESSIONID') FROM DUAL;     -- 会话ID
SELECT USERENV('LANGUAGE') FROM DUAL;      -- 语言

-- 系统信息
SELECT SYS_CONTEXT('USERENV', 'CURRENT_USER') FROM DUAL;
SELECT SYS_CONTEXT('USERENV', 'DB_NAME') FROM DUAL;
SELECT SYS_CONTEXT('USERENV', 'HOST') FROM DUAL;
SELECT SYS_CONTEXT('USERENV', 'IP_ADDRESS') FROM DUAL;

-- 唯一标识
SELECT SYS_GUID() FROM DUAL;               -- 生成唯一GUID
SELECT RAWTOHEX(SYS_GUID()) FROM DUAL;     -- 十六进制格式

七、总结 #

常用函数分类:

类别 函数 用途
字符串 SUBSTR, INSTR, REPLACE 字符串处理
日期 ADD_MONTHS, TRUNC, EXTRACT 日期计算
转换 TO_CHAR, TO_DATE, CAST 类型转换
条件 NVL, CASE, DECODE 条件判断
聚合 LISTAGG, MEDIAN 数据聚合

最佳实践:

  1. 使用NVL/COALESCE处理NULL值
  2. 使用CASE替代复杂DECODE
  3. 正则表达式处理复杂字符串
  4. 注意日期格式的一致性
  5. 合理使用函数索引优化查询

下一步,让我们学习分析函数!

最后更新:2026-03-27