声明并赋值语法
在 SQL Server 中,declare
和 set
语句用于声明变量并为其赋值,可以用一行「声明并赋值」语句来完成。
SQL
1-- 在声明时直接赋值,但这种写法只支持返回一行数据
2declare @test_id int = (select test_id from dbo.WXJ_TEST where test_code = @test_code);
⚠️ 注意:若
select
查询结果为多行,此写法会报错!
问题详解
创建测试表和插入重复数据
SQL
1-- 删除旧表(如果已存在)
2if object_id('dbo.WXJ_TEST') is not null
3 drop table dbo.WXJ_TEST;
4
5-- 创建表
6create table dbo.WXJ_TEST (
7 test_id int identity primary key,
8 test_code varchar(50) not null
9);
10
11-- 插入重复数据
12insert into dbo.WXJ_TEST (test_code) values
13('CODE001'),
14('CODE002'), -- 不同编码
15('CODE001'); -- 再来一条重复
示例一:变量声明与赋值分开
「逐步赋值:查询多行时的变量行为」,即如果查询结果有多行,则只会保留「最后一行」的 ID。
SQL
1-- 变量声明与赋值分开
2declare @test_code varchar(50); -- 声明变量
3set @test_code = 'CODE001'; -- 赋值变量
4
5declare @test_id int; -- 声明变量
6select @test_id = test_id from dbo.WXJ_TEST where test_code = @test_code; -- 赋值变量
7
8-- 返回变量结果
9-- 结果为 3,因为 CODE001 的 test_id 是 1 和 3,最后一个被赋值给 @test_id
10select @test_id as [声明与赋值分开, 最终 test_id];
示例二:单行子查询赋值
「单步赋值:多行子查询导致的赋值异常」,即子查询只能返回「一行」的 ID,若返回多行则会报错。
SQL
1-- ❌ 此语句会报错 [子查询返回的值不止一个。当子查询跟随在 =、!=、<、<=、>、>= 之后,或子查询用作表达式时,这种情况是不允许的。]
2declare @test_code2 varchar(50) = 'CODE001';
3declare @test_id2 int = (select test_id from dbo.WXJ_TEST where test_code = @test_code2);
示例三:聚合或只取一行
当查询结果可能返回多行时,必须使用聚合函数(如
max
、min
)或top (1)
来确保只返回一行数据。
方式 A:取最大 ID
SQL
1declare @test_code3 varchar(50) = 'CODE001';
2declare @test_id3 int = (
3 select max(test_id)
4 from dbo.WXJ_TEST
5 where test_code = @test_code3
6);
7
8-- 结果为 3,因为 CODE001 的最大 ID 是 3
9select @test_id3 as [取最大 ID];
方式 B:只取第一行
SQL
1declare @test_code4 varchar(50) = 'CODE001';
2declare @test_id4 int = (
3 select top (1) test_id
4 from dbo.WXJ_TEST
5 where test_code = @test_code4
6 order by test_id desc
7);
8
9-- 结果为 3,因为 CODE001 的最大 ID 是 3
10select @test_id4 as [TOP 1];
示例四:获取所有 ID 到表变量
SQL
1declare @test_code5 varchar(50) = 'CODE001';
2declare @ids table (test_id int); -- 声明表变量 @ids
3
4-- 插入多行 ID
5insert into @ids
6select test_id from dbo.WXJ_TEST where test_code = @test_code5;
7
8-- 获取所有 ID
9select * from @ids;
SQL Server 机制
变量声明与赋值分开时(select @var = ... from ...
)
- SQL Server 会遍历每一行记录,逐行赋值,每一行都会覆盖变量的值(overwrite)
- 最终,变量
@test_id
只会保存最后一行的test_id
值(last value) - 不会报错,但可能数据不是我们所期望的
合并一行赋值(declare + = (select ...)
)
- 如果返回多行,则会直接报错:
- 中文环境:子查询返回的值不止一个。当子查询跟随在 =、!=、<、<=、>、>= 之后,或子查询用作表达式时,这种情况是不允许的。
- 英文环境:Subquery returned more than 1 value. This is not permitted when the subquery follows =, !=, <, <= , >, >= or when the subquery is used as an expression.