Quali sono le differenze tra le istruzioni SET
e SELECT
quando si assegna variabili in T-SQL?
Citazione , che riepiloga da questo articolo :
- SET è lo standard ANSI per l'assegnazione di variabili, SELECT no.
- SET può solo assegnare una variabile alla volta, SELECT può eseguire più incarichi contemporaneamente.
- Se si assegna da una query, SET può solo assegnare un valore scalare. Se la query restituisce più valori/righe, SET genererà un errore. SELECT assegna uno dei valori alla variabile e nasconde il fatto che sono stati restituiti più valori (quindi probabilmente non sapresti mai perché qualcosa andasse storto altrove - divertiti a risolverlo)
- Quando si assegna da una query se non è stato restituito alcun valore, SET assegnerà NULL, dove SELECT non eseguirà affatto l'assegnazione (quindi la variabile non verrà modificata rispetto al suo valore precedente)
- Per quanto riguarda le differenze di velocità, non ci sono differenze dirette tra SET e SELECT. Tuttavia, la capacità di SELEZIONA di eseguire più compiti in un colpo gli conferisce un leggero vantaggio di velocità rispetto a SET.
Credo che SET
sia standard ANSI, mentre SELECT
non lo è. Si noti inoltre il diverso comportamento di SET
rispetto a SELECT
nell'esempio qui sotto quando non si trova un valore.
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' */
Quando si scrivono query, è necessario tenere presente questa differenza:
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*/
A parte l'ANSI e la velocità ecc., C'è una differenza molto importante che mi interessa sempre; più di ANSI e velocità. Il numero di bug che ho corretto a causa di questo importante aspetto è grande. Lo cerco durante le revisioni del codice tutto il tempo.
-- 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;
Quasi sempre, non è ciò che lo sviluppatore intende. In quanto sopra, la query è semplice ma ho visto query piuttosto complesse e capire se restituirà un singolo valore o meno, non è banale. La query è spesso più complessa di questa e per caso ha restituito un valore singolo. Durante i test degli sviluppatori va tutto bene. Ma è come una bomba a orologeria e causerà problemi quando la query restituisce più risultati. Perché? Perché assegnerà semplicemente l'ultimo valore alla variabile.
Ora proviamo la stessa cosa con SET
:
-- Act
set @employeeId = (select e.EmployeeId from dbo.Employee e);
Riceverai un errore:
La sottoquery ha restituito più di 1 valore. Questo non è permesso quando la subquery segue =,! =, <, <=,>,> = O quando la sottoquery viene usata come espressione.
Questo è sorprendente e molto importante, perché dovresti voler assegnare qualche "ultimo elemento in risultato" banale al @employeeId
. Con select
non riceverai mai alcun errore e passerai minuti, ore di debugging.
Forse, stai cercando un singolo Id e SET
ti costringerà a correggere la tua richiesta. Quindi puoi fare qualcosa come:
-- Act
-- Notice the where clause
set @employeeId = (select e.EmployeeId from dbo.Employee e where e.EmployeeId = 1);
print @employeeId;
Pulire
drop table Employee;
In conclusione, usa:
SET
: quando si desidera assegnare un singolo valore a una variabile e la variabile è per un singolo valore.SELECT
: quando si desidera assegnare più valori a una variabile. La variabile può essere una tabella, una tabella temporanea o una variabile di tabella, ecc.