首页 > 数据库 >sql存储过程和用户定义函数 (UDF) 的具体实操

sql存储过程和用户定义函数 (UDF) 的具体实操

时间:2025-01-10 11:28:29浏览次数:3  
标签:存储 VARCHAR name email UDF 实操 sql department id

存储过程和用户定义函数 (UDF) 的具体实操

为了提供更具体的实操指导,创建一个实际的数据库环境,并在此基础上编写和测试存储过程与用户定义函数(UDF)。使用MySQL作为示例数据库管理系统(DBMS),但这些概念和大部分代码可以适用于其他SQL兼容的DBMS,如PostgreSQL、SQL Server等。

环境准备

1. 创建数据库

首先,需要创建一个用于实验的数据库。假设要创建一个名为company的数据库来管理公司员工信息。

CREATE DATABASE company;
USE company;

2. 创建表结构

接下来,创建一些表来模拟公司的基本数据结构。这里将创建两个表:departments(部门信息)和 employees(员工信息)。

-- 创建部门表
CREATE TABLE departments (
    department_id INT AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(50) NOT NULL
);

-- 创建员工表
CREATE TABLE employees (
    employee_id INT AUTO_INCREMENT PRIMARY KEY,
    first_name VARCHAR(50) NOT NULL,
    last_name VARCHAR(50) NOT NULL,
    email VARCHAR(100),
    hire_date DATE NOT NULL,
    department_id INT,
    FOREIGN KEY (department_id) REFERENCES departments(department_id)
);

编写存储过程

3. 插入新员工信息的存储过程

现在将编写一个存储过程,用于插入新的员工记录到employees表中。

DELIMITER //

CREATE PROCEDURE InsertEmployee(
    IN p_first_name VARCHAR(50),
    IN p_last_name VARCHAR(50),
    IN p_email VARCHAR(100),
    IN p_hire_date DATE,
    IN p_department_id INT
)
BEGIN
    INSERT INTO employees (first_name, last_name, email, hire_date, department_id)
    VALUES (p_first_name, p_last_name, p_email, p_hire_date, p_department_id);
END //

DELIMITER ;

4. 测试存储过程

可以调用这个存储过程来添加几个测试员工。

CALL InsertEmployee('John', 'Doe', 'john.doe@example.com', '2023-01-01', 1);
CALL InsertEmployee('Jane', 'Smith', 'jane.smith@example.com', '2023-02-01', 2);

5. 获取员工总数的存储过程

接下来,创建一个带有输出参数的存储过程,用于获取当前员工总数。

DELIMITER //

CREATE PROCEDURE GetEmployeeCount(
    OUT p_count INT
)
BEGIN
    SELECT COUNT(*) INTO p_count FROM employees;
END //

DELIMITER ;

6. 调用并显示结果

调用存储过程并查看返回的结果。

CALL GetEmployeeCount(@count);
SELECT @count AS employee_count;

编写用户定义函数(UDF)

7. 计算年度薪资的标量函数

假设每个员工有一个固定的月薪,可以创建一个用户定义函数来计算他们的年度薪资。

DELIMITER //

CREATE FUNCTION CalculateAnnualSalary(
    IN p_monthly_salary DECIMAL(10,2)
)
RETURNS DECIMAL(10,2)
DETERMINISTIC
BEGIN
    DECLARE annual_salary DECIMAL(10,2);
    SET annual_salary = p_monthly_salary * 12;
    RETURN annual_salary;
END //

DELIMITER ;

8. 在查询中使用自定义函数

现在可以在查询中使用这个函数来展示每位员工的年度薪资。

SELECT 
    e.employee_id,
    CONCAT(e.first_name, ' ', e.last_name) AS full_name,
    e.email,
    e.hire_date,
    d.name AS department,
    CalculateAnnualSalary(5000) AS annual_salary -- 假设所有人的月工资都是5000
FROM 
    employees e
JOIN 
    departments d ON e.department_id = d.department_id;

错误处理与事务控制

9. 添加错误处理逻辑

在复杂的业务逻辑中,应该考虑如何处理可能发生的错误。下面是一个改进版的InsertEmployee存储过程,它包含了简单的错误处理逻辑。

DELIMITER //

CREATE PROCEDURE InsertEmployeeWithErrorHandling(
    IN p_first_name VARCHAR(50),
    IN p_last_name VARCHAR(50),
    IN p_email VARCHAR(100),
    IN p_hire_date DATE,
    IN p_department_id INT
)
BEGIN
    DECLARE exit handler for sqlexception
    BEGIN
        ROLLBACK;
        SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'An error occurred during employee insertion.';
    END;

    START TRANSACTION;
    INSERT INTO employees (first_name, last_name, email, hire_date, department_id)
    VALUES (p_first_name, p_last_name, p_email, p_hire_date, p_department_id);
    COMMIT;
END //

DELIMITER ;

10. 使用事务控制

当需要确保一系列操作要么全部成功,要么完全失败时,可以利用事务控制语句(如START TRANSACTION, COMMIT, ROLLBACK)来保证数据的一致性。上述例子中的InsertEmployeeWithErrorHandling存储过程已经展示了这一点。

实践总结

  • 命名约定:为存储过程和函数采用一致的命名规则,使其易于识别功能。
  • 文档化:为每个存储过程和函数添加注释,描述其用途、参数及返回值。
  • 错误处理:实现适当的错误捕捉和处理机制,确保程序稳健运行。
  • 测试:开发完成后,务必进行全面的单元测试以验证正确性。
  • 优化:定期审查存储过程和函数,寻找可能的性能瓶颈并加以改进。
  • 权限管理:合理分配对存储过程和函数的执行权限,保护敏感操作。

标签:存储,VARCHAR,name,email,UDF,实操,sql,department,id
From: https://blog.csdn.net/Davina_yu/article/details/145051142

相关文章

  • SQLSER中使用DATALENGTH 函数返回字符串的字节长度
    DATALENGTH函数返回字符串的字节长度,这对于varchar类型的字段非常有用,因为varchar类型的字段存储的是变长字符串,其实际占用的字节数可能小于定义的最大长度。示例假设有一个表Articles,其中有一个varchar类型的字段Content,你想查询每篇文章内容的实际占用字节数,可以使用......
  • 【Spark SQL】Join连接条件使用or导致运行慢
    现象运行的SQL示例如下selectt1.*fromedw.at1leftjoinedw.bt2on(t1.id=t2.idor((t1.idisnullort2.idisnull)andt1.phone=t2.phone))andt1.province=t2.provinceandt1.city=t2.cityandt1.type=t2.typewheret2.typeisnull;提交运行......
  • SQLSERVER截取q前300字节长度
    在SQLServer中,如果你想截取一个字符串的前300个字节,可以使用LEFT函数结合DATALENGTH函数来实现。LEFT函数用于从字符串的左侧开始截取指定长度的字符,而DATALENGTH函数用于获取字符串的实际字节长度。示例假设有一个表Articles,其中有一个varchar类型的字段Conten......
  • Mock post和get请求--实操及解释代码
    Mockpost和get请求:深入理解与实践在现代软件开发中,单元测试是确保代码质量和功能正确性的重要手段。然而,在实际开发过程中,我们经常会遇到一些难以直接测试的场景,例如依赖外部API的HTTP请求。为了解决这一问题,我们可以使用Python的unittest模块和mock库来模拟这些外部请求,......
  • pgsql 主从
    vim/home/opt/postgresql-16.0/data/postgresql.conf#设置以下listen_addresses='*'#允许远程连接hot_standby=on#打开热备wal_level=replica#设置WAL日志级别为replicamax_wal_senders=3#允许的WAL发送者数量,根据需要进行调整archive_mode=onarc......
  • 服务器上mysqld,java的进程Out of Memory,被kernel kill 掉了
    /var/log/messages里面日志如下Aug1019:47:16VM-0-7-centoskernel:8936totalpagecachepagesAug1019:47:16VM-0-7-centoskernel:0pagesinswapcacheAug1019:47:16VM-0-7-centoskernel:Swapcachestats:add0,delete0,find0/0Aug1019:47:16VM-0......
  • 使用mysqlbinlog 备份 binlog日志文件
    使用mysqlbinlog备份二进制日志文件默认情况下,mysqlbinlog读取二进制日志文件并以文本格式显示其内容。这使您能够更轻松地检查文件中的事件并重新执行它们(例如,通过将输出用作mysql的输入)。mysqlbinlog可以直接从本地文件系统读取日志文件,或者,--read-from-remote-server它可......
  • MySQL三种读取模式详解:普通、流式、游标
    在与MySQL数据库交互时,数据的读取方式有多种选择,包括普通读取、流式读取和游标读取。每种方式都有其独特的原理、优势和劣势。本文将对这三种读取方式进行详细介绍,并通过示例代码展示它们的使用方法和运行结果。1.普通读取介绍普通读取是指通过JDBC的Statement或Prepare......
  • 35岁重学网络安全——SQL注入篇(三)
    浪子回头金不换,35岁重学网络安全——SQL注入篇。本篇内容简介:MYSQL中的查询相关操作以及一些常用函数。实验环境在security库中做下列测试:usesecurity;PS:如果已经成功安装了sqli-labs的靶场,在Mysql中已经存在security库。基本查询#select+列名(*代表所有)from表......
  • 35岁重学网络安全——SQL注入篇(二)
    浪子回头金不换,35岁重学网络安全——SQL注入篇。本篇内容简介:MYSQL中库、表、行和列的基本概念与相关操作基本概念库(Database):库是数据存储的最高级别,可以看作是一个容器,用于存储相关的表集合。一个MySQL服务器可以有多个数据库,每个数据库可以独立管理,互不干扰。例如,一个......