函数、存储过程和聚集(聚合)函数

一、基本概念

1. 函数 (Function)

定义: 完成特定功能、有返回值的数据库对象
特点:

必须有返回值 (单个值或表)

可以在 SQL 语句中直接调用

通常用于计算和转换数据

不能有副作用(不能修改数据库状态)

sql 复制代码
-- 示例:标量函数(返回单个值)
CREATE FUNCTION dbo.GetEmployeeName(@EmpID INT)
RETURNS VARCHAR(100)
AS
BEGIN
    DECLARE @Name VARCHAR(100);
    SELECT @Name = Name FROM Employees WHERE EmpID = @EmpID;
    RETURN @Name;
END;

-- 使用
SELECT dbo.GetEmployeeName(1001);

-- 示例:表值函数(返回表)
CREATE FUNCTION dbo.GetEmployeesByDept(@DeptID INT)
RETURNS TABLE
AS
RETURN (
    SELECT * FROM Employees WHERE DeptID = @DeptID
);

2. 存储过程 (Stored Procedure)

定义:预编译的 SQL 代码块 ,可包含复杂的业务逻辑
特点:

可以没有返回值 ,也可以有多个返回值 (通过 OUTPUT 参数)

不能在 SQL 语句中直接调用(使用 EXEC 执行)

可以修改数据库状态 (INSERT、UPDATE、DELETE)

支持复杂的事务处理和错误处理

性能更好(预编译)

sql 复制代码
-- 示例:存储过程
CREATE PROCEDURE sp_UpdateEmployeeSalary
    @EmpID INT,
    @IncreasePercent DECIMAL(5,2),
    @NewSalary DECIMAL(10,2) OUTPUT
AS
BEGIN
    BEGIN TRANSACTION;
    TRY
        UPDATE Employees 
        SET Salary = Salary * (1 + @IncreasePercent/100)
        WHERE EmpID = @EmpID;
        
        SELECT @NewSalary = Salary FROM Employees WHERE EmpID = @EmpID;
        
        COMMIT TRANSACTION;
    END TRY
    BEGIN CATCH
        ROLLBACK TRANSACTION;
        THROW;
    END CATCH;
END;

-- 使用
DECLARE @NewSal DECIMAL(10,2);
EXEC sp_UpdateEmployeeSalary 1001, 10, @NewSal OUTPUT;

3. 聚集/聚合函数 (Aggregate Function)

定义 :对一组值进行计算返回单个值 的函数
特点

内置函数 (SUM、AVG、COUNT、MAX、MIN 等)

通常与 GROUP BY 一起使用

多行数据进行聚合计算

返回单个汇总值

sql 复制代码
-- 示例:聚合函数
SELECT 
    DeptID,
    COUNT(*) AS EmployeeCount,      -- 计数
    AVG(Salary) AS AvgSalary,       -- 平均
    SUM(Salary) AS TotalSalary,     -- 求和
    MAX(Salary) AS MaxSalary,       -- 最大
    MIN(Salary) AS MinSalary        -- 最小
FROM Employees
GROUP BY DeptID;

二、主要区别

三、联系与共同点

1. 都是数据库对象

都存储在数据库中

都可以重复使用

都能提高代码复用性

2. 都能封装逻辑

sql 复制代码
-- 函数封装计算逻辑
CREATE FUNCTION dbo.CalculateTax(@Amount DECIMAL)
RETURNS DECIMAL
AS BEGIN
    RETURN @Amount * 0.13;
END;

-- 存储过程封装业务流程
CREATE PROCEDURE sp_ProcessOrder
    @OrderID INT
AS
BEGIN
    -- 检查库存
    -- 更新订单状态
    -- 扣减库存
    -- 记录日志
END;

-- 聚合函数封装统计逻辑
SELECT AVG(Salary) FROM Employees; -- 封装了求平均的逻辑

3. 都可以带参数

sql 复制代码
-- 函数参数
SELECT dbo.GetEmployeeName(1001);

-- 存储过程参数
EXEC sp_UpdateSalary 1001, 10;

-- 聚合函数(隐式参数)
SELECT AVG(Salary) -- Salary 是隐式参数

4. 可以组合使用

sql 复制代码
-- 在存储过程中使用函数和聚合函数
CREATE PROCEDURE sp_DepartmentStats
    @DeptID INT
AS
BEGIN
    DECLARE @AvgSalary DECIMAL;
    
    -- 使用聚合函数
    SELECT @AvgSalary = AVG(Salary) 
    FROM Employees 
    WHERE DeptID = @DeptID;
    
    -- 使用自定义函数
    SELECT 
        EmpID,
        Name,
        dbo.CalculateTax(Salary) AS Tax
    FROM Employees
    WHERE DeptID = @DeptID;
END;

四、使用场景建议

✅ 使用函数的场景
需要在查询中计算或转换数据
需要返回单个值或表
逻辑相对简单,无副作用
✅ 使用存储过程的场景
复杂的业务流程
需要事务控制
需要批量处理数据
需要错误处理
多个相关操作需要一起执行
✅ 使用聚合函数的场景
统计分析
报表生成
数据汇总
GROUP BY 分组计算

五、实际例子对比

sql 复制代码
-- 1. 函数:计算员工年龄
CREATE FUNCTION dbo.CalculateAge(@BirthDate DATE)
RETURNS INT
AS
BEGIN
    RETURN DATEDIFF(YEAR, @BirthDate, GETDATE());
END;

-- 2. 存储过程:处理员工晋升
CREATE PROCEDURE sp_PromoteEmployee
    @EmpID INT,
    @NewPosition VARCHAR(50)
AS
BEGIN
    BEGIN TRANSACTION;
    
    UPDATE Employees 
    SET Position = @NewPosition,
        Salary = Salary * 1.2,
        PromoteDate = GETDATE()
    WHERE EmpID = @EmpID;
    
    INSERT INTO PromotionHistory (EmpID, NewPosition, PromoteDate)
    VALUES (@EmpID, @NewPosition, GETDATE());
    
    COMMIT TRANSACTION;
END;

-- 3. 聚合函数:统计部门信息
SELECT 
    d.DeptName,
    COUNT(e.EmpID) AS EmpCount,           -- 聚合:计数
    AVG(dbo.CalculateAge(e.BirthDate)) AS AvgAge,  -- 聚合 + 函数
    SUM(e.Salary) AS TotalBudget          -- 聚合:求和
FROM Departments d
LEFT JOIN Employees e ON d.DeptID = e.DeptID
GROUP BY d.DeptName;
相关推荐
OnlyEasyCode18 小时前
Navicat 任务自动备份指定数据库
数据库
if else18 小时前
Redis 哨兵集群部署方案
数据库·redis
yejqvow1218 小时前
Pandas 高效实现组内跨行时间戳匹配与布尔标记
jvm·数据库·python
了不起的云计算V18 小时前
从DeepSeek V4适配看国产算力的三个拐点
数据库·人工智能
qq_1898070319 小时前
html标签如何提升可访问性_aria-label与title区别【指南】
jvm·数据库·python
norq juox19 小时前
MySQL 导出数据
数据库·mysql·adb
qq_3493174819 小时前
mysql如何设置定时自动备份脚本_编写shell脚本与cron任务
jvm·数据库·python
9523619 小时前
Spring IoC&DI
java·数据库·spring
尚雷558019 小时前
从电商订单支付更新,吃透 Oracle 数据修改的底层设计哲学与全组件协同原理
数据库·oracle
2401_8323655219 小时前
Chart.js 4 中基于数据实际范围的线性渐变填充方案
jvm·数据库·python