PostgreSQL函数简介

本章将介绍PostgreSQL中的函数概念、类型和使用方法,包括内置函数和自定义函数的创建与管理。

函数概述

什么是函数

函数是PostgreSQL中预定义或用户自定义的可重用代码块,用于执行特定任务并返回结果。函数可以:

  • 执行计算:对输入参数进行计算并返回结果
  • 数据处理:处理和转换数据
  • 业务逻辑:实现复杂的业务规则
  • 代码重用:避免重复编写相同逻辑

函数类型

PostgreSQL支持多种类型的函数:

  • 内置函数:系统预定义的函数,如数学函数、字符串函数等
  • 自定义函数:用户创建的函数,使用PL/pgSQL或其他过程语言
  • 聚合函数:对一组值进行计算并返回单个结果,如SUM、COUNT等
  • 窗口函数:在结果集的行窗口上执行计算

内置函数分类

数学函数

用于执行数学计算:

SELECT 
    ABS(-10) AS absolute_value,
    SQRT(16) AS square_root,
    POWER(2, 3) AS power_result,
    ROUND(3.14159, 2) AS rounded_value,
    CEIL(3.14) AS ceiling_value,
    FLOOR(3.14) AS floor_value;

字符串函数

用于处理和操作字符串:

SELECT 
    LENGTH('Hello World') AS string_length,
    UPPER('hello') AS uppercase,
    LOWER('WORLD') AS lowercase,
    SUBSTRING('Hello World', 1, 5) AS substring_result,
    CONCAT('Hello', ' ', 'World') AS concatenated;

日期时间函数

用于处理日期和时间:

SELECT 
    CURRENT_DATE AS today,
    CURRENT_TIME AS current_time,
    NOW() AS current_timestamp,
    DATE_PART('year', CURRENT_DATE) AS current_year,
    AGE('1990-01-01'::DATE) AS age;

条件函数

根据条件返回不同结果:

SELECT 
    COALESCE(NULL, 'Default Value') AS coalesce_result,
    NULLIF(10, 10) AS nullif_result,
    GREATEST(10, 20, 30) AS greatest_value,
    LEAST(10, 20, 30) AS least_value;

自定义函数

创建简单函数

-- 创建返回两个数之和的函数
CREATE OR REPLACE FUNCTION add_numbers(a INTEGER, b INTEGER)
RETURNS INTEGER AS $$
BEGIN
    RETURN a + b;
END;
$$ LANGUAGE plpgsql;

-- 调用函数
SELECT add_numbers(5, 3); -- 返回 8

创建带默认参数的函数

-- 创建带默认参数的函数
CREATE OR REPLACE FUNCTION calculate_discount(
    price NUMERIC(10,2), 
    discount_percent NUMERIC(5,2) DEFAULT 10.00
)
RETURNS NUMERIC(10,2) AS $$
BEGIN
    RETURN price * (1 - discount_percent / 100);
END;
$$ LANGUAGE plpgsql;

-- 调用函数
SELECT calculate_discount(100.00); -- 使用默认折扣10%,返回 90.00
SELECT calculate_discount(100.00, 20.00); -- 指定折扣20%,返回 80.00

创建返回表的函数

-- 创建返回表的函数
CREATE OR REPLACE FUNCTION get_active_users()
RETURNS TABLE(
    user_id INTEGER,
    username VARCHAR(50),
    email VARCHAR(255)
) AS $$
BEGIN
    RETURN QUERY
    SELECT id, username, email
    FROM users
    WHERE is_active = true;
END;
$$ LANGUAGE plpgsql;

-- 调用函数
SELECT * FROM get_active_users();

函数管理

查看函数

-- 查看所有函数
SELECT 
    proname AS function_name,
    pg_get_function_arguments(p.oid) AS arguments,
    pg_get_function_result(p.oid) AS return_type
FROM pg_proc p
JOIN pg_namespace n ON p.pronamespace = n.oid
WHERE n.nspname = 'public';

-- 查看特定函数的定义
SELECT pg_get_functiondef('add_numbers'::regproc);

修改函数

-- 使用CREATE OR REPLACE修改函数
CREATE OR REPLACE FUNCTION add_numbers(a INTEGER, b INTEGER)
RETURNS INTEGER AS $$
BEGIN
    -- 添加日志记录
    RAISE NOTICE 'Adding % and %', a, b;
    RETURN a + b;
END;
$$ LANGUAGE plpgsql;

删除函数

-- 删除函数
DROP FUNCTION IF EXISTS add_numbers(INTEGER, INTEGER);

-- 删除重载函数
DROP FUNCTION IF EXISTS add_numbers(INTEGER, INTEGER, INTEGER);

函数最佳实践

命名规范

  • 描述性命名:函数名应清楚描述其功能
  • 一致性:在项目中保持命名风格一致
  • 避免关键字:不要使用SQL关键字作为函数名

性能考虑

  • 避免复杂逻辑:函数中避免过于复杂的业务逻辑
  • 合理使用:在大数据集上谨慎使用函数
  • 索引友好:确保函数使用不会阻止索引的使用

安全性

  • 输入验证:对所有输入参数进行验证
  • 权限控制:为函数设置适当的执行权限
  • SQL注入防护:使用参数化查询

实际应用示例

-- 创建计算订单总金额的函数
CREATE OR REPLACE FUNCTION calculate_order_total(p_order_id INTEGER)
RETURNS NUMERIC(10,2) AS $$
DECLARE
    total NUMERIC(10,2) := 0;
BEGIN
    SELECT SUM(quantity * price) INTO total
    FROM order_items
    WHERE order_id = p_order_id;
    
    RETURN COALESCE(total, 0);
END;
$$ LANGUAGE plpgsql;

-- 创建获取用户订单统计的函数
CREATE OR REPLACE FUNCTION get_user_order_stats(p_user_id INTEGER)
RETURNS TABLE(
    total_orders BIGINT,
    total_spent NUMERIC(12,2),
    avg_order_value NUMERIC(10,2),
    last_order_date DATE
) AS $$
BEGIN
    RETURN QUERY
    SELECT 
        COUNT(*) AS total_orders,
        COALESCE(SUM(total_amount), 0) AS total_spent,
        COALESCE(AVG(total_amount), 0) AS avg_order_value,
        MAX(order_date) AS last_order_date
    FROM orders
    WHERE user_id = p_user_id;
END;
$$ LANGUAGE plpgsql;

-- 使用函数
SELECT * FROM get_user_order_stats(1);

提示:合理使用函数可以提高代码的可维护性和重用性,但也要注意不要过度使用,特别是在大数据集上执行复杂函数可能会影响查询性能。