适用于:SQL Server
Azure SQL 数据库
Azure SQL 托管实例
Azure Synapse Analytics
分析平台系统 (PDW)
Microsoft Fabric
中的 SQL 分析终结点Microsoft Fabric
中的仓库Microsoft Fabric 预览版中的 SQL 数据库
变量使用语句在批处理或过程的 DECLARE 正文中声明,并使用 SET 或 SELECT 语句分配值。 游标变量可使用此语句声明,并可用于其他与游标相关的语句。 声明后,所有变量将初始化为 NULL,除非作为声明的一部分提供值。
Syntax
以下为 SQL Server 和 Azure SQL 数据库的语法:
DECLARE
{
{ @local_variable [AS] data_type [ = value ] }
| { @cursor_variable_name CURSOR }
| { @table_variable_name [AS] <table_type_definition> }
} [ , ...n ]
<table_type_definition> ::=
TABLE ( { <column_definition> | <table_constraint> | <table_index> } } [ , ...n ] )
<column_definition> ::=
column_name { scalar_data_type | AS computed_column_expression }
[ COLLATE collation_name ]
[ [ DEFAULT constant_expression ] | IDENTITY [ (seed, increment ) ] ]
[ ROWGUIDCOL ]
[ <column_constraint> ]
[ <column_index> ]
<column_constraint> ::=
{
[ NULL | NOT NULL ]
{ PRIMARY KEY | UNIQUE }
[ CLUSTERED | NONCLUSTERED ]
[ WITH FILLFACTOR = fillfactor
| WITH ( < index_option > [ , ...n ] )
[ ON { filegroup | "default" } ]
| [ CHECK ( logical_expression ) ] [ , ...n ]
}
<column_index> ::=
INDEX index_name [ CLUSTERED | NONCLUSTERED ]
[ WITH ( <index_option> [ , ... n ] ) ]
[ ON { partition_scheme_name (column_name )
| filegroup_name
| default
}
]
[ FILESTREAM_ON { filestream_filegroup_name | partition_scheme_name | "NULL" } ]
<table_constraint> ::=
{
{ PRIMARY KEY | UNIQUE }
[ CLUSTERED | NONCLUSTERED ]
( column_name [ ASC | DESC ] [ , ...n ]
[ WITH FILLFACTOR = fillfactor
| WITH ( <index_option> [ , ...n ] )
| [ CHECK ( logical_expression ) ] [ , ...n ]
}
<table_index> ::=
{
{
INDEX index_name [ UNIQUE ] [ CLUSTERED | NONCLUSTERED ]
(column_name [ ASC | DESC ] [ , ... n ] )
| INDEX index_name CLUSTERED COLUMNSTORE
| INDEX index_name [ NONCLUSTERED ] COLUMNSTORE ( column_name [ , ... n ] )
}
[ WITH ( <index_option> [ , ... n ] ) ]
[ ON { partition_scheme_name ( column_name )
| filegroup_name
| default
}
]
[ FILESTREAM_ON { filestream_filegroup_name | partition_scheme_name | "NULL" } ]
}
<index_option> ::=
{
PAD_INDEX = { ON | OFF }
| FILLFACTOR = fillfactor
| IGNORE_DUP_KEY = { ON | OFF }
| STATISTICS_NORECOMPUTE = { ON | OFF }
| STATISTICS_INCREMENTAL = { ON | OFF }
| ALLOW_ROW_LOCKS = { ON | OFF }
| ALLOW_PAGE_LOCKS = { ON | OFF }
| OPTIMIZE_FOR_SEQUENTIAL_KEY = { ON | OFF }
| COMPRESSION_DELAY = { 0 | delay [ Minutes ] }
| DATA_COMPRESSION = { NONE | ROW | PAGE | COLUMNSTORE | COLUMNSTORE_ARCHIVE }
[ ON PARTITIONS ( { partition_number_expression | <range> }
[ , ...n ] ) ]
| XML_COMPRESSION = { ON | OFF }
[ ON PARTITIONS ( { <partition_number_expression> | <range> }
[ , ...n ] ) ] ]
}
以下为 Azure Synapse Analytics、并行数据仓库和 Microsoft Fabric 的语法:
DECLARE
{ { @local_variable [AS] data_type } [ = value [ COLLATE <collation_name> ] ] } [ , ...n ]
Arguments
@ local_variable
变量的名称。 变量名必须以 at 符 (@) 开头。 局部变量名称必须符合标识符规则。
data_type
任何系统提供的公共语言运行时 (CLR) 用户定义表类型或别名数据类型。 变量的数据类型不能为 text、ntext 或 image。
有关系统数据类型的详细信息,请参阅 数据类型。 有关 CLR 用户定义的类型或别名数据类型的详细信息,请参阅 CREATE TYPE。
= 价值
以内联方式为变量赋值。 值可以是常量或表达式,但它必须与变量声明类型匹配,或者可隐式转换为该类型。 有关详细信息,请参阅 表达式。
@ cursor_variable_name
游标变量的名称。 游标变量名称必须以 at 符 (@) 开头,并符合有关标识符的规则。
CURSOR
指定变量是局部游标变量。
@ table_variable_name
table 类型的变量的名称。 变量名称必须以 at 符 (@) 开头,并符合有关标识符的规则。
table_type_definition<>
定义表数据类型。 表声明包括列定义、名称、数据类型和约束。 允许的唯一约束类型是
PRIMARY KEY,UNIQUENULL和CHECK。 如果类型绑定了规则或默认定义,则不能将别名数据类型用作列标量数据类型。
table_type_definition<>
用于定义表中 CREATE TABLE的信息子集。 其中包含了元素和主要定义。 有关详细信息,请参阅 CREATE TABLE。
n
指示可以指定多个变量并对变量赋值的占位符。 声明 表 变量时, 表 变量必须是语句中唯一声明的
DECLARE变量。
column_name
表中列的名称。
scalar_data_type
指定列是标量数据类型。
computed_column_expression
定义计算列值的表达式。 它使用同一表中的其他列从表达式中计算。 例如,计算列可以具有定义
cost AS price * qty。 表达式可以是一个或多个运算符连接的这些选项的非计算列名称、常量、内置函数、变量或这些选项的任意组合。 表达式不能为子查询或用户定义函数。 表达式不能引用 CLR 用户定义类型。
[ COLLATE collation_name ]
指定列的排序规则。 collation_name可以是 Windows 排序规则名称或 SQL 排序规则名称,并且仅适用于 char、varchar、text、nchar、nvarchar 和 ntext 数据类型的列。 如果未指定,则该列的排序规则是用户定义数据类型的排序规则(如果列为用户定义数据类型)或当前数据库的排序规则。
有关 Windows 和 SQL 排序规则名称的详细信息,请参阅 COLLATE。
DEFAULT
如果在插入过程中未显式提供值,则指定为列提供的值。
DEFAULT 定义可以应用于任何列,但定义为 时间戳 或属性的 IDENTITY 列除外。
DEFAULT 删除表时会删除定义。 只有常量值,例如字符串;系统函数(如 SYSTEM_USER();)或 NULL 可用作默认值。 为了保持与早期版本的 SQL Server 的兼容性,可以将约束名称分配给一个 DEFAULT。
constant_expression
常量或
NULL系统函数,用作列的默认值。
IDENTITY
指示新列是标识列。 在表中添加新行时,SQL Server 将为列提供一个唯一的增量值。 标识列通常用于 PRIMARY KEY 约束,用作表的唯一行标识符。 该IDENTITY属性可以分配给 tinyint、smallint、int、decimal(p,0)或 numeric(p,0) 列。 每个表只能创建一个标识列。 绑定的默认值和 DEFAULT 约束不能与标识列一起使用。 必须同时指定种子和增量,或者都不指定。 如果二者都未指定,则取默认值 (1,1)。
seed
用于表中所加载的第一行的值。
increment
添加到以前装载的列标识值的增量值。
ROWGUIDCOL
指示新列是行的全局唯一标识符列。 每个表只能指定一个 uniqueidentifier 列作为 ROWGUIDCOL 列。 该 ROWGUIDCOL 属性只能分配给 uniqueidentifier 列。
NULL |NOT NULL
指示变量中是否允许使用 Null。 默认值为 NULL。
主键
通过唯一索引对给定的一列或多列强制实现实体完整性的约束。 每个表只能创建一个 PRIMARY KEY 约束。
UNIQUE
通过唯一索引为给定的一列或多列提供实体完整性的约束。 表可以有多个 UNIQUE 约束。
CLUSTERED |NONCLUSTERED
指示为 PRIMARY KEY 或 UNIQUE 约束创建聚集索引或非聚集索引。
PRIMARY KEY 约束用法 CLUSTERED和 UNIQUE 约束使用 NONCLUSTERED。
CLUSTERED 只能为一个约束指定。 如果 CLUSTERED 为 UNIQUE 约束指定,并且 PRIMARY KEY 还指定了约束,则 PRIMARY KEY 使用 NONCLUSTERED。
CHECK
一个约束,该约束通过限制可输入一列或多列中的可能值来强制实现域完整性。
logical_expression
TRUE返回或FALSE.
<index_option>
指定一个或多个索引选项。 不能显式创建 table 变量的索引,也不保留 table 变量的任何统计信息 。 SQL Server 2014 (12.x) 引入了语法,允许你创建某些索引类型,并嵌入表定义。 使用此语法,可以在表定义过程中对表变量创建索引。 在某些情况下,性能可能会改用临时表,从而提供完整的索引支持和统计信息。
有关这些操作的完整说明,请参阅 CREATE TABLE。
表变量和行预估
Table 变量没有分发统计信息。 在许多情况下,优化器基于表变量具有零行或一行的假设生成查询计划。 有关详细信息,请查看表数据类型 - 限制和局限。
出于这一原因,如果您预计会存在大量行(超过 100 行),那么在使用 table 变量时应小心谨慎。 请考虑以下替代方法:
当行计数可能更大(大于 100)时,临时表可能是比表变量更好的解决方案。
对于将表变量与其他表联接的查询,请使用
RECOMPILE提示,这会导致优化器对表变量使用正确的基数。在 Azure SQL 数据库中,从 SQL Server 2019(15.x 开始),表变量延迟编译功能会传播基于实际表变量行计数的基数估计,从而提供更准确的行计数来优化执行计划。 有关详细信息,请参阅 SQL 数据库中的智能查询处理。
Remarks
变量通常用于批处理或过程中作为计数器 WHILE, LOOP或块 IF...ELSE 。
变量只能用在表达式中,不能代替对象名或关键字。 若要构造动态 SQL 语句,请使用 EXECUTE。
局部变量的作用域是其被声明时所在批处理。
表变量不一定是内存驻留。 在内存压力下,可以将属于表变量的页推送到 tempdb。
可以在表变量中定义内联索引。
当前分配有游标的游标变量可在下列语句中作为源引用:
-
CLOSE陈述 -
DEALLOCATE陈述 -
FETCH陈述 -
OPEN陈述 -
DELETE定位或UPDATE语句 -
SET CURSORvariable 语句(右侧)
在所有上述语句中,如果存在被引用的游标变量,但是不具有当前分配给它的游标,那么 SQL Server 将引发错误。 如果不存在被引用的游标变量,SQL Server 将引发与其他类型的未声明变量引发的错误相同的错误。
游标变量:
可以是游标类型或其他游标变量的目标。 有关详细信息,请参阅 SET @local_variable。
如果游标变量当前未向其分配游标,则可以在语句中
EXECUTE作为输出游标参数的目标引用。应被看作是指向游标的指针。
Examples
本文中的代码示例使用 AdventureWorks2022 或 AdventureWorksDW2022 示例数据库,可以从 Microsoft SQL Server 示例和社区项目 主页下载该数据库。
A. 使用 DECLARE
以下示例使用一个局部变量来 @find 检索以开头的所有家族名称的 Man联系信息。
USE AdventureWorks2022;
GO
DECLARE @find AS VARCHAR (30);
/* Also allowed:
DECLARE @find VARCHAR(30) = 'Man%';
*/
SET @find = 'Man%';
SELECT p.LastName,
p.FirstName,
ph.PhoneNumber
FROM Person.Person AS p
INNER JOIN Person.PersonPhone AS ph
ON p.BusinessEntityID = ph.BusinessEntityID
WHERE LastName LIKE @find;
结果集如下。
LastName FirstName Phone
------------------- ----------------------- -------------------------
Manchepalli Ajay 1 (11) 500 555-0174
Manek Parul 1 (11) 500 555-0146
Manzanares Tomas 1 (11) 500 555-0178
B. 将 DECLARE 与两个变量配合使用
下例将检索北美销售区中年销售额至少为 $2,000,000 的 Adventure Works Cycles 销售代表的名字。
USE AdventureWorks2022;
GO
SET NOCOUNT ON;
GO
DECLARE @Group AS NVARCHAR (50), @Sales AS MONEY;
SET @Group = N'North America';
SET @Sales = 2000000;
SET NOCOUNT OFF;
SELECT FirstName,
LastName,
SalesYTD
FROM Sales.vSalesPerson
WHERE TerritoryGroup = @Group
AND SalesYTD >= @Sales;
C. 声明类型表的变量
以下示例创建一个table变量,用于存储语句子句UPDATE中指定的OUTPUT值。 在它后面的两个 SELECT 语句返回 @MyTableVar 中的值以及 Employee 表中更新操作的结果。
INSERTED.ModifiedDate 列中的结果与 ModifiedDate 表的 Employee 列中的值不同。 这是因为对 AFTER UPDATE 表定义了 ModifiedDate 触发器,该触发器可以将 Employee 的值更新为当前日期。 不过,从 OUTPUT 返回的列可反映触发器激发之前的数据。 有关详细信息,请参阅 OUTPUT 子句。
USE AdventureWorks2022;
GO
DECLARE @MyTableVar TABLE (
EmpID INT NOT NULL,
OldVacationHours INT,
NewVacationHours INT,
ModifiedDate DATETIME);
UPDATE TOP (10) HumanResources.Employee
SET VacationHours = VacationHours * 1.25
OUTPUT INSERTED.BusinessEntityID,
DELETED.VacationHours,
INSERTED.VacationHours,
INSERTED.ModifiedDate
INTO @MyTableVar;
--Display the result set of the table variable.
SELECT EmpID,
OldVacationHours,
NewVacationHours,
ModifiedDate
FROM @MyTableVar;
GO
--Display the result set of the table.
--Note that ModifiedDate reflects the value generated by an
--AFTER UPDATE trigger.
SELECT TOP (10) BusinessEntityID,
VacationHours,
ModifiedDate
FROM HumanResources.Employee;
GO
D. 使用内联索引声明类型表的变量
以下示例创建具有一个聚集内联索引和两个非聚集内联索引的 table 变量。
DECLARE @MyTableVar TABLE (
EmpID INT NOT NULL,
PRIMARY KEY CLUSTERED (EmpID),
UNIQUE NONCLUSTERED (EmpID),
INDEX CustomNonClusteredIndex NONCLUSTERED (EmpID));
GO
以下查询返回有关在上一个查询中创建的索引的信息。
SELECT * FROM tempdb.sys.indexes
WHERE object_id < 0;
GO
E. 声明用户定义的表类型的变量
下面的示例将创建一个名为 @LocationTVP 的表值参数或表变量。 此步骤需要一个名为 LocationTableType 的相应用户定义表类型。
有关如何创建用户定义的表类型的详细信息,请参阅 CREATE TYPE。 有关表值参数的详细信息,请参阅使用表值参数(数据库引擎)。
DECLARE @LocationTVP AS LocationTableType;
示例:Azure Synapse Analytics 和 Analytics Platform System (PDW)
F. 使用 DECLARE
以下示例使用一个局部变量来 @find 检索以开头的所有家族名称的 Walt联系信息。
-- Uses AdventureWorks
DECLARE @find AS VARCHAR (30);
/* Also allowed:
DECLARE @find VARCHAR(30) = 'Man%';
*/
SET @find = 'Walt%';
SELECT LastName,
FirstName,
Phone
FROM DimEmployee
WHERE LastName LIKE @find;
G. 将 DECLARE 与两个变量配合使用
以下示例检索使用变量来指定表中雇员 DimEmployee 的第一个和系列名称。
DECLARE @lastName AS VARCHAR (30),
@firstName AS VARCHAR (30);
SET @lastName = 'Walt%';
SET @firstName = 'Bryan';
SELECT LastName,
FirstName,
Phone
FROM DimEmployee
WHERE LastName LIKE @lastName
AND FirstName LIKE @firstName;