SET与选择时分配变量?

在T-SQL中分配变量时,SETSELECT语句之间有什么区别?

425261 次浏览

报价,它总结了这篇文章:

  1. SET是用于变量赋值的ANSI标准,SELECT不是。
  2. SET一次只能赋值一个变量,SELECT一次可以赋值多个变量。
  3. 如果从查询赋值,SET只能赋值一个标量值。如果查询返回多个值/行,则SET将引发错误。SELECT将把其中一个值赋给变量,并隐藏返回多个值的事实(因此您可能永远不知道为什么在其他地方出现了错误-请愉快地排除故障)
  4. 当从查询中赋值时,如果没有返回值,则SET将赋值为NULL,其中SELECT将根本不进行赋值(因此变量将不会从之前的值改变)
  5. 至于速度差异——SET和SELECT之间没有直接的差异。然而,SELECT在一个镜头中进行多个赋值的能力确实使它比SET有轻微的速度优势。

我相信SET是ANSI标准,而SELECT不是。还要注意下例中SETSELECT在找不到值时的不同行为。

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' */

在编写查询时,应该记住这个区别:

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和速度。由于这个重要的疏忽,我修复的bug数量很大。我一直在检查代码时寻找这一点。

-- 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:当你想给一个变量赋多个值时。变量可以是表,临时表或表变量等。
环绕select with()中的所有内容。 确保你只返回一个项目 如< / p >
ET @sql_update =  (select left(@sql_update, len(@sql_update)-1))
SET @Telephone2 = (SELECT REPLACE(LTRIM(REPLACE(@Telephone2, '0', ' ')), ' ', '0'))