变量 (Transact-SQL)

适用于:SQL ServerAzure SQL 数据库Azure SQL 托管实例Azure Synapse AnalyticsAnalytics Platform System (PDW)Microsoft Fabric 中的 SQL 分析终结点Microsoft Fabric 中的仓库

Transact-SQL 局部变量是可以保存单个特定类型数据值的对象。 批处理和脚本中的变量通常用于:

  • 作为计数器,可以计算执行循环的次数,或控制循环的执行次数。
  • 保存数据值以供控制流语句测试。
  • 保存存储过程返回代码要返回的数据值或函数返回值。

注解

一些 Transact-SQL 系统函数的名称以两个 at 符号 (@@) 开头。 尽管在早期版本的 SQL Server 中,函数 @@ 称为全局变量, @@ 但函数不是变量,它们的行为与变量不同。 这些 @@ 函数是系统函数,其语法用法遵循函数的规则。

不能在视图中使用变量。

事务回滚不影响对变量所做的更改。

声明 Transact-SQL 变量

DECLARE 语句通过以下方式初始化 Transact-SQL 变量:

  • 指定一个名称。 名称的首字符必须为一个 @

  • 指定系统提供的或用户定义的数据类型和长度。 对于数值变量还指定精度和小数位数。 对于 XML 类型的变量,可以分配可选的架构集合。

  • 将值设置为 NULL.

例如,以下DECLARE语句创建一个名为 int 数据类型的局部变量@mycounter。 默认情况下,此变量的值为 NULL.

DECLARE @MyCounter INT;

若要声明多个局部变量,请在定义的第一个局部变量后使用一个逗号,然后指定下一个局部变量名称和数据类型。

例如,以下 DECLARE 语句将创建三个名为 @LastName@FirstName@StateProvince/> 的局部变量,并将每个变量初始化为 NULL

DECLARE @LastName NVARCHAR(30), @FirstName NVARCHAR(20), @StateProvince NCHAR(2);

变量的作用域就是可以引用该变量的 Transact-SQL 语句的范围。 变量的范围从声明的点持续到声明它的批处理或存储过程的末尾。 例如,以下脚本生成语法错误,因为变量在一个批处理中声明(由GO关键字 (keyword)分隔)并在另一个批中引用:

USE AdventureWorks2022;
GO

DECLARE @MyVariable INT;

SET @MyVariable = 1;
GO

SELECT BusinessEntityID,
    NationalIDNumber,
    JobTitle
FROM HumanResources.Employee
WHERE BusinessEntityID = @MyVariable;

变量具有局部范围,并且仅在定义变量的批处理或过程中可见。 在下面的示例中,为执行 sp_executesql 而创建的嵌套作用域无权访问在较高作用域中声明的变量,并返回和错误。

DECLARE @MyVariable INT;
SET @MyVariable = 1;
EXECUTE sp_executesql N'SELECT @MyVariable'; -- this produces an error

在 Transact-SQL 变量中设置值

首次声明变量时,其值设置为 NULL。 若要向变量赋值,请使用 SET 语句。 这是为变量赋值的首选方法。 变量还可以通过在语句的选择 SELECT 列表中被引用来分配值。

若要通过使用 SET 语句为变量赋值,请包含变量名和需要赋给变量的值。 这是为变量赋值的首选方法。 例如,下面的批处理声明两个变量、为它们赋值并在 WHERE 语句的 SELECT 子句中予以使用:

USE AdventureWorks2022;
GO

-- Declare two variables.
DECLARE @FirstNameVariable NVARCHAR(50),
    @PostalCodeVariable NVARCHAR(15);

-- Set their values.
SET @FirstNameVariable = N'Amy';
SET @PostalCodeVariable = N'BA5 3HX';

-- Use them in the WHERE clause of a SELECT statement.
SELECT LastName,
    FirstName,
    JobTitle,
    City,
    StateProvinceName,
    CountryRegionName
FROM HumanResources.vEmployee
WHERE FirstName = @FirstNameVariable
    OR PostalCode = @PostalCodeVariable;
GO

变量也可以通过选择列表中当前所引用的值赋值。 如果在选择列表中引用变量,则应为其分配标量值,否则 SELECT 语句应仅返回一行。 例如:

USE AdventureWorks2022;
GO
DECLARE @EmpIDVariable INT;

SELECT @EmpIDVariable = MAX(EmployeeID)
FROM HumanResources.Employee;
GO

警告

如果单个 SELECT 语句中有多个赋值子句,SQL Server 不保证表达式的计算顺序。 仅当赋值之间有引用时,效果才可见。

SELECT如果语句返回多个行,并且变量引用非标表达式,则变量将设置为结果集中最后一行中为表达式返回的值。 例如,在以下批处理 @EmpIDVariable 中,设置为 BusinessEntityID 返回的最后一行的值,即 1

USE AdventureWorks2022;
GO
DECLARE @EmpIDVariable INT;

SELECT @EmpIDVariable = BusinessEntityID
FROM HumanResources.Employee
ORDER BY BusinessEntityID DESC;

SELECT @EmpIDVariable;
GO

示例

以下脚本创建一个小的测试表并向其填充 26 行。 脚本使用变量来执行下列三个操作:

  • 通过控制循环执行的次数来控制插入的行数。
  • 提供插入整数列的值。
  • 作为表达式一部分生成插入字符列的字母的函数。
-- Create the table.
CREATE TABLE TestTable (cola INT, colb CHAR(3));
GO

SET NOCOUNT ON;
GO

-- Declare the variable to be used.
DECLARE @MyCounter INT;

-- Initialize the variable.
SET @MyCounter = 0;

-- Test the variable to see if the loop is finished.
WHILE (@MyCounter < 26)
BEGIN;
    -- Insert a row into the table.
    INSERT INTO TestTable
    VALUES
        -- Use the variable to provide the integer value
        -- for cola. Also use it to generate a unique letter
        -- for each row. Use the ASCII function to get the
        -- integer value of 'a'. Add @MyCounter. Use CHAR to
        -- convert the sum back to the character @MyCounter
        -- characters after 'a'.
        (
        @MyCounter,
        CHAR((@MyCounter + ASCII('a')))
        );

    -- Increment the variable to count this iteration
    -- of the loop.
    SET @MyCounter = @MyCounter + 1;
END;
GO

SET NOCOUNT OFF;
GO

-- View the data.
SELECT cola, colb FROM TestTable;
GO

DROP TABLE TestTable;
GO