¿SET versus SELECT al asignar variables?

Resuelto juur asked hace 14 años • 5 respuestas

¿Cuáles son las diferencias entre las declaraciones SETy SELECTal asignar variables en T-SQL?

juur avatar Oct 16 '10 02:10 juur
Aceptado

Cita que resume este artículo :

  1. SET es el estándar ANSI para asignación de variables, SELECT no lo es.
  2. SET solo puede asignar una variable a la vez, SELECT puede realizar múltiples asignaciones a la vez.
  3. Si se asigna desde una consulta, SET solo puede asignar un valor escalar. Si la consulta devuelve varios valores/filas, SET generará un error. SELECT asignará uno de los valores a la variable y ocultará el hecho de que se devolvieron varios valores (por lo que probablemente nunca sabrás por qué algo salió mal en otro lugar; diviértete solucionando ese problema).
  4. Al asignar desde una consulta, si no se devuelve ningún valor, SET asignará NULL, donde SELECT no realizará la asignación en absoluto (por lo que la variable no cambiará de su valor anterior)
  5. En cuanto a las diferencias de velocidad, no existen diferencias directas entre SET y SELECT. Sin embargo, la capacidad de SELECT para realizar múltiples asignaciones de una sola vez le da una ligera ventaja de velocidad sobre SET.
OMG Ponies avatar Oct 15 '2010 19:10 OMG Ponies

Creo SETque es el estándar ANSI, mientras que SELECTno lo es. Tenga en cuenta también el comportamiento diferente de SETvs. SELECTen el siguiente ejemplo cuando no se encuentra un valor.

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' */
Joe Stefanelli avatar Oct 15 '2010 19:10 Joe Stefanelli

Al redactar consultas, se debe tener en cuenta esta diferencia:

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*/
GorkemHalulu avatar Aug 27 '2015 08:08 GorkemHalulu

Aparte de ANSI y velocidad, etc., hay una diferencia muy importante que siempre me importa; más que ANSI y velocidad. La cantidad de errores que he solucionado debido a este importante descuido es grande. Busco esto durante las revisiones de código todo el tiempo.

-- 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; 

Casi siempre, eso no es lo que pretende el desarrollador. En lo anterior, la consulta es sencilla, pero he visto consultas que son bastante complejas y determinar si devolverá un valor único o no no es trivial. La consulta suele ser más compleja que esto y, por casualidad, ha devuelto un valor único. Durante las pruebas de desarrollador, todo está bien. Pero esto es como una bomba de tiempo y causará problemas cuando la consulta arroje múltiples resultados. ¿Por qué? Porque simplemente asignará el último valor a la variable.

Ahora intentemos lo mismo con SET:

 -- Act
 set @employeeId = (select e.EmployeeId from dbo.Employee e);

Recibirás un error:

La subconsulta devolvió más de 1 valor. Esto no está permitido cuando la subconsulta sigue a =, !=, <, <=, >, >= o cuando la subconsulta se utiliza como expresión.

Esto es sorprendente y muy importante porque ¿por qué querrías asignar un "último elemento del resultado" trivial al archivo @employeeId. Con selectél nunca obtendrá ningún error y pasará minutos y horas depurando.

Quizás esté buscando una identificación única y SETlo obligue a corregir su consulta. Por lo tanto, puedes hacer algo como:

-- Act
-- Notice the where clause
set @employeeId = (select e.EmployeeId from dbo.Employee e where e.EmployeeId = 1);
print @employeeId;

Limpiar

drop table Employee;

En conclusión, utilice:

  • SET: Cuando desea asignar un valor único a una variable y su variable es para un valor único.
  • SELECT: cuando desea asignar múltiples valores a una variable. La variable puede ser una tabla, una tabla temporal o una variable de tabla, etc.
CodingYoshi avatar Apr 04 '2019 15:04 CodingYoshi