数据库存储过程和SQL PSM


存储过程对于数据库管理系统 (DBMS) 至关重要,因为它们可以提高安全性、提升性能并促进代码重用。存储过程是预编译的数据库对象,包含一组 SQL 语句。它们存储在数据库中,可以被应用程序或其他数据库对象调用。在这篇文章中,我们将深入探讨 SQL 持久存储模块 (PSM) 的细节,这是一种 SQL 的过程化编程语言扩展,并考察存储过程的概念。

了解存储过程

存储过程是预编译并存储在数据库中的数据库对象,包含一组 SQL 语句。它们存储在数据库中,可以被应用程序或其他数据库对象调用。让我们来看一个简单的 SQL Server 存储过程示例:

CREATE PROCEDURE GetEmployeeById
    @EmployeeId INT
AS
BEGIN
    SELECT * FROM Employees WHERE EmployeeId = @EmployeeId
END

输入表 - 员工

+------------+--------------+------------+
| EmployeeId | EmployeeName | Department |
+------------+--------------+------------+
| 1          | John Doe     | HR         |
| 2          | Jane Smith   | IT         |
| 3          | Mike Johnson | Sales      |
| 4          | Sarah Adams  | Marketing  |
| 5          | Robert Brown | Finance    |
| 6          | Lisa Davis   | HR         |
| 7          | David Wilson | IT         |
| 8          | Emily Lee    | Sales      |
| 9          | Michael Chen | Marketing  |
| 10         | Olivia Clark | Finance    |
+------------+--------------+------------+

以上代码定义了名为 "GetEmployeeById" 的存储过程,它接受输入参数 @Employee Id。该过程根据提供的 Employee Id 从 "Employees" 表中提取员工信息。

可以使用以下代码来执行存储过程:

EXEC GetEmployeeById @EmployeeId = 1

输出表

+------------+--------------+------------+
| EmployeeId | EmployeeName | Department |
+------------+--------------+------------+
| 1          | John Doe     | HR         |
+------------+--------------+------------+

这将使用 Employee Id 等于 1 来执行存储过程并获取员工信息。

使用存储过程的好处

  • 性能提升 − 存储过程是预编译的,并以编译形式存储在数据库中,从而减少了与解析和编译相关的开销。与动态生成的 SQL 语句相比,这导致更快的执行速度。

  • 代码重用性 − 存储过程鼓励模块化编程和代码重用。它们可以从多个程序或其他存储过程中调用,从而减少重复并促进一致性。

  • 安全性 − 存储过程提供额外的安全层,允许在过程级别进行访问控制。应用程序可以被授权执行特定的操作,同时限制对表的直接访问。

  • 数据完整性 − 将复杂的数据修改算法封装到存储过程中可以更有效地确保数据完整性。由于逻辑包含在数据库中,因此可以提供可靠且一致的结果。

向 SQL 添加过程化功能 (SQL PSM)

SQL 持久存储模块 (PSM) 是 SQL 过程化编程语言的扩展。它允许开发人员在数据库中创建函数和过程,从而实现高级数据处理和操作。让我们通过一些实际示例来探讨 SQL PSM 的一些主要特性。

  • 过程化结构

  • 过程特定标记语言 (PSM) 提供了过程化构造,包括条件语句 (IF、CASE)、循环 (WHILE、FOR) 和异常处理 (TRY-CATCH)。请查看以下示例,了解如何在 PSM 中使用条件语句:

示例

CREATE PROCEDURE GetEmployeeSalaryRange
    @MinSalary DECIMAL(10,2),
    @MaxSalary DECIMAL(10,2)
AS
BEGIN
    IF @MinSalary <= @MaxSalary
    BEGIN
        SELECT * FROM Employees WHERE Salary BETWEEN @MinSalary AND @MaxSalary
    END
    ELSE
    BEGIN
        RAISERROR('Invalid salary range.', 16, 1)
    END
END

输入表 - 员工

| EmployeeId | EmployeeName | Salary    |
|------------|--------------|-----------|
| 1          | John Doe     | 50000.00  |
| 2          | Jane Smith   | 65000.00  |
| 3          | Mike Johnson | 75000.00  |
| 4          | Lisa Davis   | 45000.00  |
| 5          | Mark Wilson  | 80000.00  |
| 6          | Sarah Brown  | 55000.00  |
| 7          | Alex Lee     | 60000.00  |
| 8          | Emily Clark  | 70000.00  |
| 9          | David Jones  | 40000.00  |
| 10         | Olivia Smith | 90000.00  |

输出表

结果假设过程 GetEmployeeSalaryRange 被调用,输入参数 @MinSalary = 50000.00 和 @MaxSalary = 70000.00。

| EmployeeId | EmployeeName | Salary    |
|------------|--------------|-----------|
| 1          | John Doe     | 50000.00  |
| 2          | Jane Smith   | 65000.00  |
| 3          | Mike Johnson | 75000.00  |
| 6          | Sarah Brown  | 55000.00  |
| 7          | Alex Lee     | 60000.00  |
| 8          | Emily Clark  | 70000.00  |

此代码中的存储过程 "GetEmployeeSalaryRange" 接受输入参数 @MinSalary 和 @MaxSalary。它使用 IF 语句有条件地检索薪资在指定范围内的员工。如果 @MinSalary 高于 @MaxSalary,则 RAISERROR 语句会引发错误。

  • 变量支持

  • PSM 允许定义和使用变量,这些变量可以存储输入/输出值或用于存储中间结果。让我们来看一个存储过程使用变量执行计算的示例:

CREATE PROCEDURE CalculateTotalSalary
    @EmployeeId INT,
    @BonusPercentage DECIMAL(5,2) OUTPUT,
    @TotalSalary DECIMAL(10,2) OUTPUT
AS
BEGIN
    DECLARE @BaseSalary DECIMAL(10,2)

    SELECT @BaseSalary = Salary FROM Employees WHERE EmployeeId = @EmployeeId
    SET @BonusPercentage = 0.1
    SET @TotalSalary = @BaseSalary + (@BaseSalary * @BonusPercentage)
END

此代码中的存储过程 "CalculateTotalSalary" 通过将基本工资乘以奖金百分比来计算员工的总工资。它使用输入参数 @Employee Id 从 "Employees" 表中检索员工的基本工资。计算出的奖金百分比和总工资分别存储在输出参数 @Bonus Percentage 和 '@Total Salary' 中。

我们可以使用以下代码来执行存储过程并获取计算值:

DECLARE @Bonus DECIMAL(5,2)
DECLARE @Total DECIMAL(10,2)

EXEC CalculateTotalSalary @EmployeeId = 1, @BonusPercentage = @Bonus OUTPUT, @TotalSalary = @Total OUTPUT

SELECT @Bonus AS BonusPercentage, @Total AS TotalSalary

输入表 - 员工

| EmployeeId | Salary  |
|------------|---------|
| 1          | 5000.00 |
| 2          | 6000.00 |
| 3          | 4500.00 |
| 4          | 7000.00 |
| 5          | 5500.00 |
| 6          | 8000.00 |
| 7          | 4000.00 |
| 8          | 6500.00 |
| 9          | 7500.00 |
| 10         | 5200.00 |

输出表

| EmployeeId | BonusPercentage | TotalSalary |
|------------|-----------------|-------------|
| 1          | 0.10            | 5500.00     |
| 2          | 0.10            | 6600.00     |
| 3          | 0.10            | 4950.00     |
| 4          | 0.10            | 7700.00     |
| 5          | 0.10            | 6050.00     |
| 6          | 0.10            | 8800.00     |
| 7          | 0.10            | 4400.00     |
| 8          | 0.10            | 7150.00     |
| 9          | 0.10            | 8250.00     |
| 10         | 0.10            | 5720.00     |


  • 错误处理

  • PSM 中的 TRY-CATCH 构造提供了可靠的错误处理机制。让我们来看一个如何在存储过程中使用 TRY-CATCH 来处理错误的示例:

CREATE PROCEDURE DivideNumbers
    @Dividend INT,
    @Divisor INT
AS
BEGIN
    BEGIN TRY
        SELECT @Dividend / @Divisor AS Result
    END TRY
    BEGIN CATCH
        SELECT ERROR_NUMBER() AS ErrorNumber, ERROR_MESSAGE() AS ErrorMessage
    END CATCH
END

此代码中的存储过程 "Divide Numbers" 执行两个数字 @Dividend 和 @Divisor 的除法。它在 TRY 块中尝试除法,如果发生错误,则激活 CATCH 块,使用 ERROR_NUMBER() 和 ERROR_MESSAGE() 函数检索和显示错误信息。

输入表 - 员工

+----------+---------+
| Dividend | Divisor |
+----------+---------+
|    10    |    2    |
|    20    |    4    |
|    15    |    3    |
|    30    |    5    |
|    12    |    4    |
|    18    |    6    |
|    25    |    5    |
|    16    |    2    |
|    35    |    7    |
|    40    |    8    |
+----------+---------+

可以使用以下代码来执行存储过程并处理任何错误:

EXEC DivideNumbers @Dividend = 10, @Divisor = 0

输出表

+--------------+---------------------------------+
| ErrorNumber  |         ErrorMessage           |
+--------------+---------------------------------+
|    8134      |  Divide by zero error encountered. |
+--------------+---------------------------------+

这将导致除以零错误,并且 CATCH 块将被激活以显示错误号和消息。

  • 函数定义 − SQL 持久存储模块 (PSM) 允许在数据库中定义函数。函数是可以重用的代码块,它们接受输入参数,执行某些操作并返回单个值。它们可以像任何其他 SQL 表达式一样在 SQL 查询中使用。以下是如何在 SQL PSM 中定义函数的示例:

CREATE FUNCTION GetEmployeeCountByDepartment(departmentId INT)
    RETURNS INT
BEGIN
    DECLARE @Count INT

    SELECT @Count = COUNT(*) FROM Employees WHERE DepartmentId = departmentId

    RETURN @Count
END

以上代码定义了名为 "GetEmployeeCountByDepartment" 的函数,它接受输入参数 departmentId。该函数计算指定部门中的员工数量,并返回一个整数结果。

输入表 - 员工

+------------+--------------+--------------+
| EmployeeId | EmployeeName | DepartmentId |
+------------+--------------+--------------+
|     1      |   John Doe   |      1       |
|     2      |  Jane Smith  |      1       |
|     3      | Mark Johnson |      2       |
|     4      |  Emily Brown |      3       |
|     5      |  Alex Wilson |      2       |
|     6      |  Sarah Davis |      1       |
|     7      | Mike Thompson|      3       |
|     8      |   Emma Lee   |      2       |
|     9      | James Miller |      1       |
|    10      | Lily Anderson|      3       |
+------------+--------------+--------------+

部门表

+--------------+----------------+
| DepartmentId | DepartmentName |
+--------------+----------------+
|      1       |    Sales       |
|      2       |   Marketing    |
|      3       |    Finance     |
|      4       |      HR        |
|      5       |      IT        |
+--------------+----------------+

可以使用以下代码在 SQL 查询中使用此函数:

SELECT DepartmentId, GetEmployeeCountByDepartment(DepartmentId) AS EmployeeCount
FROM Departments

输出表

+--------------+---------------+
| DepartmentId | EmployeeCount |
+--------------+---------------+
|      1       |       4       |
|      2       |       3       |
|      3       |       2       |
|      4       |       0       |
|      5       |       0       |
+--------------+---------------+

此查询从 "Departments" 数据库中检索部门 ID,然后对每个部门执行 "Get Employee Count By Department" 函数以获取相应的员工数量。

SQL PSM 的好处

使用 SQL PSM 在数据库开发中有很多优势。

  • 增强功能 − 通过包含过程化结构和变量支持,PSM 扩展了 SQL 的功能。这允许开发人员直接在数据库中执行复杂的业务逻辑和数据转换,从而消除了将数据传输和处理到 DBMS 之外的必要性。

  • 性能提升 − PSM 通过在数据库中直接执行逻辑来减少数据库和外部应用程序之间传输数据的开销。这减少了网络延迟并提高了性能。

  • 代码重用性和可维护性 − 通过将逻辑封装在过程和函数中,PSM 鼓励代码重用。开发人员可以创建可供其他应用程序使用的模块化代码,从而减少重复并提高可维护性。

  • 数据完整性和安全性 − PSM 通过将数据处理和操作逻辑包含在数据库中来确保数据一致性和完整性。PSM 还提供细粒度的访问控制,通过限制对表的直接访问并仅向应用程序公开必要的过程来提高安全性。

结论

总之,SQL PSM 和存储过程是强大的工具,可以提高数据库系统的可用性、可靠性、安全性以及数据完整性。开发人员可以通过利用这些功能来提高应用程序的速度、优化代码并确保在数据库中执行可靠且安全的数据操作。无论是管理复杂的数据转换还是执行业务规则,存储过程和 SQL PSM 都为高效且可靠的数据库开发提供了坚实的基础。

更新于: 2023年8月2日

1K+ 浏览量

开启您的职业生涯

完成课程并获得认证

立即开始
广告