Cuándo utilizar SET vs SELECT al asignar valores a las variables en SQL Server
SET y SELECT pueden ser usados para asignar valores a las variables a través de T-SQL. Ambos cumplen su tarea, pero en algunos casos se pueden producir resultados inesperados. En este artículo menciono detalles sobre las consideraciones para elegir entre los métodos SET y SELECT al asignar un valor a una variable.
En la mayoría de los casos SET y SELECT pueden ser utilizados alternativamente sin ningún efecto.
Los siguientes son algunos de los escenarios que requieren consideración en la elección entre SET o SELECT. Para mas aclaraciones usaremos scripts para la base de datos AdventureWorks.
Cada script a continuación se compone de parte 1 y parte 2. Sería mejor si ejecutas cada parte de los scripts por separado para que puedas ver los resultados de cada método.
Retornando valores a través de una consulta
Cada vez que es asignando un valor a una variable mediante una consulta, SET aceptará y asignara un escalar (solo) un valor de una consulta. Mientras SELECT podría aceptar múltiples valores devueltos. Pero después de aceptar varios valores a través del comando SELECT no tienes manera de rastrear que valor está en la variable. El último valor devuelto en la lista llenará la variable. Debido a esta situación puede conducir a resultados no esperados, ya que no se genera ningún error o advertencia si varios valores fueron devueltos al usar el SELECT. Así pues, si varios valores se podría esperar utilizar la opción SET con la correcta aplicación de los mecanismos de control de errores.
Para aclarar más el concepto por favor ejecuta el siguiente script #1 en dos partes por separado para ver los resultados
Script #1. Uso de SET para asignar valores
USE AdventureWorks GO -- Part1. Populate by single row through SET DECLARE @Var1ForSet varchar(50) SET @Var1ForSet = (SELECT [Name] FROM Production.Product WHERE ProductNumber = 'HY-1023-70') PRINT @Var1ForSet GO -- Part 2. Populate by multiple rows through SET DECLARE @Var2ForSet varchar(50) SET @Var2ForSet = (SELECT [Name] FROM Production.Product WHERE Color = 'Silver') PRINT @Var2ForSet GO
La parte 1 del script tendrá éxito. La variable se rellena con un valor único través de la SET. Pero en la parte 2 del script el siguiente mensaje de error se produce y la instrucción SET dejará de llenar la variable cuando se devuelve más de un valor.
Mensaje de error generado para SET
Msg 512, Level 16, State 1, Line 4
Subquery returned more than 1 value. This is not permitted when the subquery follows =, !=, <, <= , >, >= or when the subquery is used as an expression.
Por ello SET previene la asignacion de valores ambiguos.
En caso de SELECT, aunque los valores devueltos por la consulta son varios, no genera error y no ganrá manera de rastrear que varios valores fueron devueltos y que valor está en la variable. Eso se demuestra en el siguiente script:
Script #2. Usar SELECT para asignar valores
USE AdventureWorks GO -- Part1. Populate by single row through SELECT DECLARE @Var1ForSelect varchar(50) SET @Var1ForSelect = (SELECT [Name] FROM Production.Product WHERE ProductNumber = 'HY-1023-70') PRINT @Var1ForSelect GO -- Part2. Populate by multiple rows through SELECT DECLARE @Var2ForSelect varchar(50) SELECT @Var2ForSelect = [Name] FROM Production.Product WHERE Color = 'Silver' PRINT @Var2ForSelect GO
Tanto la parte 1 como la parte 2 fueron ejecutadas con éxito. En la parte 2 varios valores se asignaron y aceptaron, sin sabe qué valor realmente se usó. Así cuando se espera la recuperación de varios valores luego de considerar las diferencias de comportamiento entre SET y SELECT e implementar el manejo de errores para estas circunsatancias.
Asignar múltiples valores a múltiples variables
Si tienes que poblar múltiples variables, en lugar de utilizar instrucciones SET por separado cada vez, considera el uso de SELECT para poblar todas las variables en una sola instrucción. Esto puede ser usado para poblar las variables en forma directa o mediante la selección de valores desde la base de datos.
Considera el siguiente script que compara el uso de SELECT y SET:
Script #3. Poblar múltiples variables a través de SELECT
USE AdventureWorks GO -- Part 1. Assign direct values to multiple variables DECLARE @var1 VARCHAR(50) DECLARE @var2 VARCHAR(50) DECLARE @var3 VARCHAR(50) SELECT @var1 = 'Value1', @var2 = 'Value2', @var3 = 'Value3' PRINT @var1 PRINT @var2 PRINT @var3 GO -- Part 2. Assign retrieved values to multiple variables DECLARE @name VARCHAR(50) DECLARE @productNo VARCHAR(25) DECLARE @color VARCHAR(15) SELECT @name = [Name], @productNo = ProductNumber, @color = Color FROM Production.Product WHERE ProductID = 320 PRINT @name PRINT @productNo PRINT @color GO
Si estás usando SET, entonces cada varible debe tener asignado valores individualmente a través de múltiples instrucciones como se muestra a continuación:
Script #4. Poblar múltiples variables a través de SET
USE AdventureWorks GO -- Part 1. Assign direct values to multiple variables DECLARE @var1 VARCHAR(50) DECLARE @var2 VARCHAR(50) DECLARE @var3 VARCHAR(50) SET @var1 = 'Value1' SET @var2 = 'Value2' SET @var3 = 'Value3' PRINT @var1 PRINT @var2 PRINT @var3 GO -- Part 2. Assign retrieved values to multiple variables DECLARE @name VARCHAR(50) DECLARE @productNo VARCHAR(25) DECLARE @color VARCHAR(15) SET @name =(SELECT [Name] FROM Production.Product WHERE ProductID = 320) SET @productNo = (SELECT ProductNumber FROM Production.Product WHERE ProductID = 320) SET @color = (SELECT Color FROM Production.Product WHERE ProductID = 320) PRINT @name PRINT @productNo PRINT @color GO
Obviamente SELECT es mas eficiente que SET mientras asigna valores a múltiples variables en términos de instrucciones ejecutadas, código y bytes de red.
¿Qué si la variable no se pobla con éxito?
Si una variable no es poblada con éxito entonces el comportamiento de SET y SELECT sería diferente. Fallas en la asignación puede ser debido a que ningún resultado es devuelto o cualquier otro valor no compatible con la variable. En este caso, SELECT preservará el valor anterior, si lo hubiere, donde SET retornará NULL. Debido a la diferente funcionalidad, ambos pueden conducir a resultados inesperados y se deben considerar con cuidado.
Esto se demuestra en el siguiente script:
Script# 5. Comportamiento de SET y SELECT para valor faltante
USE AdventureWorks GO -- Part 1. Observe behavior of missing result with SET DECLARE @var1 VARCHAR(20) SET @var1 = 'Value 1 Assigned' PRINT @var1 SET @var1 = (SELECT Color FROM Production.Product WHERE ProductID = 32022) PRINT @var1 GO -- Part 1. Observe behavior of missing result with SELECT DECLARE @var1 VARCHAR(20) SELECT @var1 = 'Value 1 Assigned' PRINT @var1 SELECT @var1 = Color FROM Production.Product WHERE ProductID = 32023 PRINT @var1 GO
Podemos observar que la parte 1 genera NULL cuando no devuelve ningun valor para poblar la variable. en cambio la parte 2 produce el valor previo que se conserva despues de la asignacion fallida de la variable. Esta situación puede conducir a resultados inesperados y requiere consideración.
Siguiendo los estandares
Usar SELECT puede parecer la mejor opción para escenarios especificos, pero ten en cuenta que SELECT se usa para asignar valores a las variables no esta incluido en los estandares ANSI. Si sigues los estandares para fines de migracion de código, entonces evita el uso de SELECT y usa SET en su lugar.
Conclusión
Las mejores prácticas no apegarse a un método. Según los escenarios es posible que desee utilizar tanto SET como SELECT.
A continuación se presentan algunos escenarios para usar SET:
- Si estás obligado a asignar un solo valor directamente a la variable y no hay consulta para buscar el valor.
- Se esperan asignaciones NULL (retorna NULL en un conjunto de resultados).
- Los estandares están destinados a pasar cualquier plan de migración.
- Se esperan resultados no escalares y deben ser manipulados.
Usando SELECT es eficiente y flexible en los siguientes casos:
- Múltiples variables están siendo pobladas por asignación directa de valores.
- Múltiples variables están siendo pobladas por una unica fuente (tabla, vista).
- Menos codigo para asignar multiples variables.
- Usa esta opción si necesitas @ROWCOUNT y @ERROR de la última sentencia ejecutada.
Entradas relacionadas