SQL Server笔记 -- 第50章 存储过程

在 SQL Server 中,存储过程是可接收参数的可复用程序,不返回值(如函数那样),但可返回执行状态。

第50.1节 创建并执行基本存储过程

使用 Library 数据库的 Authors 表:

sql 复制代码
CREATE PROCEDURE GetName
    @input_id INT = NULL,        -- 输入参数:人员 ID,默认 NULL
    @name    VARCHAR(128) = NULL -- 输入参数:姓名,默认 NULL
AS
BEGIN
    SELECT Name + ' is from ' + Country
    FROM Authors
    WHERE Id = @input_id OR Name = @name;
END
GO

执行方式:

  1. 使用 EXECUTE / EXEC
sql 复制代码
EXECUTE GetName @input_id = 1;
EXEC GetName @name = 'Ernest Hemingway';
  1. 省略 EXEC,直接调用
sql 复制代码
GetName NULL, 'Ernest Hemingway';
  1. 参数顺序可任意,只要显式指定:
sql 复制代码
CREATE PROC dbo.sProcTemp
    @Param1 INT,
    @Param2 INT
AS
SELECT Param1 = @Param1, Param2 = @Param2;

-- 调用
EXEC dbo.sProcTemp @Param2 = 0, @Param1 = 1;
  1. sp_ 开头并放在 master 数据库中的存储过程可在任意数据库中直接调用(优先搜索 master)。

第50.2节 带 IF...ELSE 与 INSERT 的存储过程

示例表:

sql 复制代码
CREATE TABLE Employee (
    Id          INT,
    EmpName     VARCHAR(25),
    EmpGender   VARCHAR(6),
    EmpDeptId   INT
);

存储过程:检查参数非空后插入。

sql 复制代码
CREATE PROCEDURE spSetEmployeeDetails
    @ID       INT,
    @Name     VARCHAR(25),
    @Gender   VARCHAR(6),
    @DeptId   INT
AS
BEGIN
    IF (
        @ID IS NOT NULL AND LEN(@ID) != 0
        AND @Name IS NOT NULL AND LEN(@Name) != 0
        AND @Gender IS NOT NULL AND LEN(@Gender) != 0
        AND @DeptId IS NOT NULL AND LEN(@DeptId) != 0
    )
    BEGIN
        INSERT INTO Employee (Id, EmpName, EmpGender, EmpDeptId)
        VALUES (@ID, @Name, @Gender, @DeptId);
    END
    ELSE
        PRINT 'Incorrect Parameters';
END
GO

调用:

sql 复制代码
DECLARE @ID INT, @Name VARCHAR(25), @Gender VARCHAR(6), @DeptId INT;

EXEC spSetEmployeeDetails
    @ID = 1,
    @Name = 'Subin Nepal',
    @Gender = 'Male',
    @DeptId = 182666;

第50.3节 存储过程中的动态 SQL

当表名、列名或过滤值需在运行时决定,可拼接并执行动态 SQL。

sql 复制代码
CREATE PROC sp_dynamicSQL
    @table_name NVARCHAR(20),
    @col_name   NVARCHAR(20),
    @col_value  NVARCHAR(20)
AS
BEGIN
    DECLARE @Query NVARCHAR(MAX);
    SET @Query = 'SELECT * FROM ' + QUOTENAME(@table_name)
               + ' WHERE ' + QUOTENAME(@col_name) + ' = @val';
    EXEC sp_executesql @Query, N'@val NVARCHAR(20)', @val = @col_value;
END

调用:

sql 复制代码
DECLARE @table NVARCHAR(20) = 'ITCompanyInNepal',
        @col   NVARCHAR(20) = 'Headquarter',
        @val   NVARCHAR(20) = 'USA';

EXEC sp_dynamicSQL @table, @col, @val;
  • 使用 QUOTENAME 避免注入
  • 复杂场景可拼接更长脚本,实现多表/多条件动态查询

第50.4节 带 OUTPUT 参数的存储过程

存储过程可通过 OUTPUT 关键字返回值。

  1. 单输出参数示例
sql 复制代码
CREATE PROC SprocWithOutParams
    @InParam  VARCHAR(30),
    @OutParam VARCHAR(30) OUTPUT
AS
BEGIN
    SET @OutParam = @InParam + ' must come out';
    RETURN;
END
GO

-- 调用
DECLARE @Out VARCHAR(30);
EXEC SprocWithOutParams 'what goes in', @Out OUTPUT;
PRINT @Out;
  1. 多输出参数
sql 复制代码
CREATE PROC SprocWithOutParams2
    @InParam  VARCHAR(30),
    @Out1     VARCHAR(30) OUTPUT,
    @Out2     VARCHAR(30) OUTPUT
AS
BEGIN
    SET @Out1 = @InParam + ' must come out';
    SET @Out2 = @InParam + ' must come out';
    RETURN;
END
GO

-- 调用
DECLARE @O1 VARCHAR(30), @O2 VARCHAR(30);
EXEC SprocWithOutParams2 'what goes in', @O1 OUTPUT, @O2 OUTPUT;
PRINT @O1; PRINT @O2;

第50.5节 简单循环(遍历)

先准备临时数据:

sql 复制代码
SELECT
    o.name,
    ROW_NUMBER() OVER (ORDER BY o.name) AS rn
INTO #systables
FROM sys.objects o
WHERE o.type = 'S';

循环脚本:

sql 复制代码
DECLARE @rn INT = 1, @maxRn INT = (SELECT MAX(rn) FROM #systables);
DECLARE @tablename SYSNAME;

WHILE @rn <= @maxRn
BEGIN
    SELECT @tablename = name, @rn = @rn + 1
    FROM #systables
    WHERE rn = @rn;

    PRINT @tablename;
END

第50.6节 简单循环(指定次数打印)

sql 复制代码
CREATE PROC SprocWithSimpleLoop
    @SayThis      VARCHAR(30),
    @ThisManyTimes INT
AS
BEGIN
    WHILE @ThisManyTimes > 0
    BEGIN
        PRINT @SayThis;
        SET @ThisManyTimes = @ThisManyTimes - 1;
    END
    RETURN;
END
GO

调用:

sql 复制代码
EXEC SprocWithSimpleLoop 'Hello, World!', 3;

输出:

复制代码
Hello, World!
Hello, World!
Hello, World!
相关推荐
2301_777599378 分钟前
mysql如何进行数据库容量规划_评估磁盘空间增长趋势
jvm·数据库·python
NineData44 分钟前
NineData 亮相香港国际创科展 InnoEX 2026,以 AI 加速布局全球市场
运维·数据库·人工智能·ninedata·新闻资讯·玖章算术
m0_3776182344 分钟前
Redis怎样应对大规模集群的重启风暴_分批次重启节点并等待集群状态恢复绿灯后再继续操作
jvm·数据库·python
imuliuliang1 小时前
存储过程(SQL)
android·数据库·sql
考虑考虑1 小时前
SQL语句中的order by可能造成时间重复
数据库·后端·mysql
2401_835956812 小时前
Golang怎么写基准测试benchmark_Golang基准测试教程【完整】
jvm·数据库·python
一嘴一个橘子2 小时前
sql 的 count、avg
sql
南境十里·墨染春水2 小时前
C++ 笔记 thread
java·开发语言·c++·笔记·学习
南境十里·墨染春水2 小时前
C++ 笔记 高级线程同步原语与线程池实现
java·开发语言·c++·笔记·学习
lkforce2 小时前
MiniMind学习笔记(二)--model_minimind.py
笔记·python·学习·minimind·minimindconfig