Réponses:
Citation , qui résume cet article :
- SET est la norme ANSI pour l'attribution des variables, SELECT ne l'est pas.
- SET ne peut affecter qu'une seule variable à la fois, SELECT peut effectuer plusieurs affectations à la fois.
- En cas d'affectation à partir d'une requête, SET ne peut affecter qu'une valeur scalaire. Si la requête renvoie plusieurs valeurs / lignes, SET génère une erreur. SELECT affectera l'une des valeurs à la variable et masquera le fait que plusieurs valeurs ont été renvoyées (vous ne saurez donc probablement jamais pourquoi quelque chose ne va pas ailleurs - amusez-vous à résoudre ce problème)
- Lors de l'affectation à partir d'une requête si aucune valeur n'est retournée, SET affectera NULL, où SELECT ne fera pas du tout l'affectation (donc la variable ne sera pas modifiée par rapport à sa valeur précédente)
- En ce qui concerne les différences de vitesse - il n'y a pas de différences directes entre SET et SELECT. Cependant, la capacité de SELECT à effectuer plusieurs affectations en une seule fois lui confère un léger avantage sur la vitesse par rapport à SET.
SELECT @Int = @Int + 1, @Int = @Int + 1
s'il est @Int
démarré à 0, il se termine alors à 2. Cela peut être très utile lors de manipulations de chaînes successives.
Je crois que SET
c'est la norme ANSI alors que ce SELECT
n'est pas le cas. Notez également le comportement différent de SET
vs SELECT
dans l'exemple ci-dessous lorsqu'une valeur n'est pas trouvée.
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' */
select @var = (select name from master.sys.tables where name = 'qwerty')
vous obtiendrez @var comme nul. L'exemple que vous donnez n'est pas la même requête.
(select name from master.sys.tables where name = 'qwerty')
pour l'un et name from master.sys.tables where name = 'qwerty'
pour l'autre ... vous ne voyez pas ça?
(select name from master.sys.tables where name = 'qwerty')
est une sous-requête scalaire et name from master.sys.tables where name = 'qwerty'
est une requête simple. Les deux expressions différentes ne sont pas censées produire les mêmes résultats, bien qu'il semble que vous sous-entendiez qu'elles le devraient. Si vous essayez de dire que les mots clés SET
et SELECT
ont des implémentations différentes, vous ne devez pas utiliser deux expressions différentes dans vos exemples. msdn.microsoft.com/en-us/library/ms187330.aspx
Lors de l'écriture de requêtes, cette différence doit être gardée à l'esprit:
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*/
Mis à part celui qui est ANSI et la vitesse, etc., il y a une différence très importante qui compte toujours pour moi; plus que ANSI et la vitesse. Le nombre de bugs que j'ai corrigés en raison de cette importante négligence est important. Je recherche cela pendant les révisions de code tout le temps.
-- 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;
Presque toujours, ce n'est pas l'intention du développeur. Dans ce qui précède, la requête est simple mais j'ai vu des requêtes qui sont assez complexes et déterminer si elle retournera une valeur unique ou non, n'est pas trivial. La requête est souvent plus complexe que cela et, par hasard, elle a renvoyé une seule valeur. Pendant les tests des développeurs, tout va bien. Mais cela ressemble à une bombe à retardement et causera des problèmes lorsque la requête renvoie plusieurs résultats. Pourquoi? Parce qu'il affectera simplement la dernière valeur à la variable.
Essayons maintenant la même chose avec SET
:
-- Act
set @employeeId = (select e.EmployeeId from dbo.Employee e);
Vous recevrez une erreur:
La sous-requête a renvoyé plus d'une valeur. Cela n'est pas autorisé lorsque la sous-requête suit =,! =, <, <=,>,> = Ou lorsque la sous-requête est utilisée comme expression.
C'est étonnant et très important, car pourquoi voudriez-vous attribuer un "dernier élément de résultat" trivial au @employeeId
. Avec select
vous, vous n'obtiendrez jamais d'erreur et vous passerez des minutes, des heures à déboguer.
Peut-être que vous recherchez un seul identifiant et SET
vous obligerez à corriger votre requête. Ainsi, vous pouvez faire quelque chose comme:
-- Act
-- Notice the where clause
set @employeeId = (select e.EmployeeId from dbo.Employee e where e.EmployeeId = 1);
print @employeeId;
Nettoyer
drop table Employee;
En conclusion, utilisez:
SET
: Lorsque vous souhaitez affecter une seule valeur à une variable et que votre variable est pour une seule valeur.SELECT
: Lorsque vous souhaitez affecter plusieurs valeurs à une variable. La variable peut être une table, une table temporaire ou une variable de table, etc.