Respostas:
Citação , que resume este artigo :
- SET é o padrão ANSI para atribuição de variáveis, SELECT não é.
- O SET pode atribuir apenas uma variável por vez, o SELECT pode fazer várias atribuições ao mesmo tempo.
- Ao atribuir a partir de uma consulta, o SET só pode atribuir um valor escalar. Se a consulta retornar vários valores / linhas, o SET gerará um erro. SELECT atribuirá um dos valores à variável e ocultará o fato de que vários valores foram retornados (portanto, você provavelmente nunca saberia por que algo estava errado em outro lugar - divirta-se solucionando problemas com esse)
- Ao atribuir a partir de uma consulta se não houver valor retornado, o SET atribuirá NULL, em que SELECT não fará a atribuição de todo (portanto, a variável não será alterada em relação ao valor anterior)
- Quanto às diferenças de velocidade - não há diferenças diretas entre SET e SELECT. No entanto, a capacidade do SELECT de fazer várias atribuições de uma só vez oferece uma pequena vantagem de velocidade em relação ao SET.
SELECT @Int = @Int + 1, @Int = @Int + 1
se @Int
iniciado como 0, termina como 2. Isso pode ser muito útil ao fazer manipulações sucessivas de strings.
Eu acredito que SET
é o padrão ANSI, enquanto o SELECT
não é. Observe também o comportamento diferente de SET
vs. SELECT
no exemplo abaixo quando um valor não for encontrado.
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')
, obteria @var como nulo. O exemplo que você está dando não é a mesma consulta.
(select name from master.sys.tables where name = 'qwerty')
um e name from master.sys.tables where name = 'qwerty'
o outro ... você não vê isso?
(select name from master.sys.tables where name = 'qwerty')
é uma subconsulta escalar e name from master.sys.tables where name = 'qwerty'
é uma consulta simples. As duas expressões diferentes não devem produzir os mesmos resultados, embora pareça que você está sugerindo que elas deveriam. Se você está tentando dizer que as palavras SET
- SELECT
chave e têm implementações diferentes, não deve usar duas expressões diferentes nos seus exemplos. msdn.microsoft.com/en-us/library/ms187330.aspx
Ao escrever consultas, essa diferença deve ser lembrada:
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*/
Além de ANSI e velocidade, etc., há uma diferença muito importante que sempre importa para mim; mais do que ANSI e velocidade. O número de bugs que eu consertei devido a essa negligência importante é grande. Eu procuro isso durante revisões de código o tempo todo.
-- 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;
Quase sempre, não é isso que o desenvolvedor pretende. No exposto, a consulta é direta, mas já vi consultas bastante complexas e descobrir se retornará um valor único ou não, não é trivial. A consulta geralmente é mais complexa que essa e, por acaso, está retornando valor único. Durante o teste do desenvolvedor, tudo está bem. Mas isso é como uma bomba-relógio e causará problemas quando a consulta retornar vários resultados. Por quê? Porque simplesmente atribui o último valor à variável.
Agora vamos tentar a mesma coisa com SET
:
-- Act
set @employeeId = (select e.EmployeeId from dbo.Employee e);
Você receberá um erro:
Subconsulta retornou mais de 1 valor. Isso não é permitido quando a subconsulta segue =,! =, <, <=,>,> = Ou quando a subconsulta é usada como uma expressão.
Isso é incrível e muito importante, porque por que você deseja atribuir algum "último item no resultado" trivial ao arquivo @employeeId
. Com select
você nunca receberá nenhum erro e você passará minutos, horas depurando.
Talvez você esteja procurando um único ID e SET
forçará você a corrigir sua consulta. Assim, você pode fazer algo como:
-- Act
-- Notice the where clause
set @employeeId = (select e.EmployeeId from dbo.Employee e where e.EmployeeId = 1);
print @employeeId;
Limpar
drop table Employee;
Em conclusão, use:
SET
: Quando você deseja atribuir um único valor a uma variável e sua variável é para um único valor.SELECT
: Quando você deseja atribuir vários valores a uma variável. A variável pode ser uma tabela, tabela temporária ou variável de tabela etc.