Answers:
- SET是用于变量分配的ANSI标准,而SELECT不是。
- SET一次只能分配一个变量,SELECT可以一次进行多个分配。
- 如果从查询分配,则SET只能分配标量值。如果查询返回多个值/行,则SET将引发错误。SELECT会将值之一分配给变量,并隐藏返回多个值的事实(因此您很可能永远都不知道为什么其他地方出了问题-对该故障排除进行有趣的故障排除)
- 从查询分配时,如果没有返回值,则SET将分配NULL,而SELECT根本不会进行赋值(因此该变量将不会从其先前的值更改)
- 至于速度差异-SET和SELECT之间没有直接差异。但是,SELECT一次完成多个任务的能力确实使其速度比SET稍有优势。
SELECT @Int = @Int + 1, @Int = @Int + 1
如果@Int
从0开始,然后以2结尾。这在进行连续的字符串操作时非常有用。
我相信这SET
是ANSI标准,而事实SELECT
并非如此。还请注意,在下面的示例中,当找不到值时,SET
vs SELECT
。的行为不同。
declare @var varchar(20)
set @var = 'Joe'
set @var = (select name from master.sys.tables where name = 'qwerty')
select @var /* @var is now NULL */
set @var = 'Joe'
select @var = name from master.sys.tables where name = 'qwerty'
select @var /* @var is still equal to 'Joe' */
select @var = (select name from master.sys.tables where name = 'qwerty')
,则将@var设置为null。您提供的示例是不同的查询。
(select name from master.sys.tables where name = 'qwerty')
一个,而name from master.sys.tables where name = 'qwerty'
另一个...您看不到吗?
(select name from master.sys.tables where name = 'qwerty')
是标量子查询,并且name from master.sys.tables where name = 'qwerty'
是简单查询。尽管您似乎暗示他们应该这样做,但两个不同的表达式不应产生相同的结果。如果您试图说SET
and SELECT
关键字具有不同的实现,则不应在示例中使用两个不同的表达式。msdn.microsoft.com/en-us/library/ms187330.aspx
在编写查询时,应牢记这种差异:
DECLARE @A INT = 2
SELECT @A = TBL.A
FROM ( SELECT 1 A ) TBL
WHERE 1 = 2
SELECT @A
/* @A is 2*/
---------------------------------------------------------------
DECLARE @A INT = 2
SET @A = (
SELECT TBL.A
FROM ( SELECT 1 A) TBL
WHERE 1 = 2
)
SELECT @A
/* @A is null*/
除了ANSI和速度等之外,还有一个非常重要的差异对我始终很重要;超过ANSI和速度。由于这一重要的疏忽,我修复的错误数量很多。我一直在代码审查期间寻找这个。
-- Arrange
create table Employee (EmployeeId int);
insert into dbo.Employee values (1);
insert into dbo.Employee values (2);
insert into dbo.Employee values (3);
-- Act
declare @employeeId int;
select @employeeId = e.EmployeeId from dbo.Employee e;
-- Assert
-- This will print 3, the last EmployeeId from the query (an arbitrary value)
-- Almost always, this is not what the developer was intending.
print @employeeId;
几乎总是,这不是开发人员想要的。在上面的查询中,查询很简单,但是我看到的查询非常复杂,弄清楚它是否返回单个值并不是一件容易的事。查询通常比这更复杂,并且偶然地它一直在返回单个值。在开发人员测试期间,一切都很好。但这就像一枚滴答作响的炸弹,当查询返回多个结果时将引起问题。为什么?因为它将仅将最后一个值分配给变量。
现在让我们尝试使用SET
:
-- Act
set @employeeId = (select e.EmployeeId from dbo.Employee e);
您将收到一个错误:
子查询返回的值超过1。当子查询遵循=,!=,<,<=,>,> =或将子查询用作表达式时,不允许这样做。
这真是太神奇了,而且非常重要,因为您为什么要为分配一些琐碎的“结果中的最后一项” @employeeId
。用select
您将永远不会收到任何错误,并且将花费数分钟,数小时进行调试。
也许,您正在寻找一个ID,这SET
将迫使您修复查询。因此,您可以执行以下操作:
-- Act
-- Notice the where clause
set @employeeId = (select e.EmployeeId from dbo.Employee e where e.EmployeeId = 1);
print @employeeId;
清理
drop table Employee;
总之,使用:
SET
:当您要为变量分配单个值并且您的变量用于单个值时。SELECT
:要为变量分配多个值时。该变量可以是表,临时表或表变量等。