¿SET versus SELECT al asignar variables?
¿Cuáles son las diferencias entre las declaraciones SET
y SELECT
al asignar variables en T-SQL?
Cita que resume este artículo :
- SET es el estándar ANSI para asignación de variables, SELECT no lo es.
- SET solo puede asignar una variable a la vez, SELECT puede realizar múltiples asignaciones a la vez.
- 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).
- 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)
- 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.
Creo SET
que es el estándar ANSI, mientras que SELECT
no lo es. Tenga en cuenta también el comportamiento diferente de SET
vs. SELECT
en 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' */
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*/
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 SET
lo 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.