SET contro SELECT durante l'assegnazione delle variabili?


Risposte:


411

Citazione , che riassume da questo articolo :

  1. SET è lo standard ANSI per l'assegnazione delle variabili, mentre SELECT non lo è.
  2. SET può assegnare una sola variabile alla volta, SELECT può eseguire più assegnazioni contemporaneamente.
  3. Se si assegna da una query, SET può assegnare solo un valore scalare. Se la query restituisce più valori / righe, SET genererà un errore. SELECT assegnerà uno dei valori alla variabile e nasconderà il fatto che sono stati restituiti più valori (quindi probabilmente non sapresti mai perché qualcosa non andava altrove - divertiti a risolverlo)
  4. Quando si assegna da una query se non viene restituito alcun valore, SET assegnerà NULL, dove SELECT non eseguirà affatto l'assegnazione (quindi la variabile non verrà modificata dal suo valore precedente)
  5. Per quanto riguarda le differenze di velocità, non ci sono differenze dirette tra SET e SELECT. Tuttavia, la capacità di SELECT di eseguire più incarichi in un colpo solo gli conferisce un leggero vantaggio di velocità rispetto a SET.

3
Non ho effettuato il downgrade, ma non è del tutto corretto: "Per quanto riguarda le differenze di velocità - non ci sono differenze dirette tra SET e SELECT". Se si assegnano più valori in una sola schermata, ciò può essere molto più veloce rispetto a insiemi multipli. Google up "L'assegnazione di più variabili con una SELECT funziona più velocemente"
AK,

14
@AlexKuznetsov: la frase in seguito dice esattamente questo.
OMG Pony

3
Pony @OMG: può essere 10 volte più veloce o più, quindi non sono sicuro che si tratti di "leggero vantaggio di velocità".
AK,

2
Soprattutto quando ho usato un While-Loop, ho visto enormi miglioramenti delle prestazioni impostando / reinizializzando tutte le mie variabili usando one-Select vs. many-Set's. Posso anche consolidare la mia variabile-logica in un Select da eseguire contemporaneamente: Esempio:, SELECT @Int = @Int + 1, @Int = @Int + 1se @Intavviato come 0, termina come 2. Ciò può essere molto utile quando si eseguono successive manipolazioni di stringhe.
MikeTeeVee,

Discussione interessante sulla differenza di prestazioni. Se l'impostazione di più valori tramite select è più veloce (codificare ed eseguire), un modo sicuro per evitare il punto 4 (il valore della variabile che non cambia se la query restituisce null) è di impostare esplicitamente la variabile su null prima della selezione. Una volta che lo consideri, come si confrontano i due per le prestazioni? (Nota a margine: non capisco la logica per cui selezionare non impostare la variabile su null nel caso in cui una query restituisca null. Quando mai lo vorresti?)
youcantryreachingme

155

Credo SETsia lo standard ANSI mentre non lo SELECTè. Si noti inoltre il diverso comportamento di SETvs. SELECTnell'esempio seguente quando non viene trovato 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' */

4
+1 È meglio correre una volta per capire, controllare, giocare, memorizzarlo per leggere ma altre risposte sono solo testo
Gennady Vanin Геннадий Ванин

4
Se effettivamente utilizzato select @var = (select name from master.sys.tables where name = 'qwerty')si otterrebbe @var come null. L'esempio che stai dando non è la stessa query.
Zack,

4
Ce l'hai (select name from master.sys.tables where name = 'qwerty')per uno e name from master.sys.tables where name = 'qwerty'per l'altro ... non lo vedi?
Zack,

4
@Zack: Ognuno è la sintassi corretta per quello che sto cercando di provare; la differenza tra l'utilizzo di SET vs. SELECT per assegnare un valore a una variabile quando la query sottostante non restituisce risultati.
Joe Stefanelli,

5
(select name from master.sys.tables where name = 'qwerty')è una sottoquery scalare ed name from master.sys.tables where name = 'qwerty'è una query semplice. Le due diverse espressioni non dovrebbero produrre gli stessi risultati, anche se sembra che tu stia insinuando che dovrebbero. Se stai cercando di dire che le parole chiave SETe SELECThanno implementazioni diverse, non dovresti usare due espressioni diverse nei tuoi esempi. msdn.microsoft.com/en-us/library/ms187330.aspx
Zack

27

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*/

molto bello, succinto
SimplyInk,

8

A parte quello che è ANSI e velocità ecc., C'è una differenza molto importante che conta sempre per me; più di ANSI e velocità. Il numero di bug che ho corretto a causa di questo aspetto importante è grande. Lo cerco continuamente durante le revisioni del codice.

-- 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 è questo lo scopo dello sviluppatore. In quanto sopra, la query è semplice ma ho visto query abbastanza 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 questo è come una bomba che spunta 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 subquery ha restituito più di 1 valore. Ciò non è consentito quando la sottoquery segue =,! =, <, <=,>,> = O quando la sottoquery viene utilizzata come espressione.

Questo è sorprendente e molto importante perché perché vorresti assegnare qualche banale "ultimo elemento nel risultato" al @employeeId. Con selectte non otterrai mai alcun errore e passerai minuti, ore a eseguire il debug.

Forse stai cercando un singolo ID e SETti costringerà a correggere la tua query. Quindi puoi fare qualcosa del tipo:

-- 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, utilizzare:

  • 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.
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.