【发布时间】:2011-04-26 02:42:29
【问题描述】:
在T-SQL中赋值变量时SET和SELECT语句有什么区别?
【问题讨论】:
标签: sql sql-server sql-server-2005 tsql sql-server-2008
在T-SQL中赋值变量时SET和SELECT语句有什么区别?
【问题讨论】:
标签: sql sql-server sql-server-2005 tsql sql-server-2008
Quote,总结自this article:
- 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 与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为空。您给出的示例不是同一个查询。
(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 和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:当你想为一个变量分配多个值时。变量可以是表、临时表或表变量等。【讨论】: