SET versus SELECT beim Zuweisen von Variablen?


Antworten:


411

Zitat , das aus diesem Artikel zusammenfasst :

  1. SET ist der ANSI-Standard für die Variablenzuweisung, SELECT nicht.
  2. SET kann jeweils nur eine Variable zuweisen, SELECT kann mehrere Zuweisungen gleichzeitig vornehmen.
  3. Bei der Zuweisung aus einer Abfrage kann SET nur einen Skalarwert zuweisen. Wenn die Abfrage mehrere Werte / Zeilen zurückgibt, löst SET einen Fehler aus. SELECT weist der Variablen einen der Werte zu und verbirgt die Tatsache, dass mehrere Werte zurückgegeben wurden (sodass Sie wahrscheinlich nie wissen würden, warum anderswo etwas schief gelaufen ist - viel Spaß bei der Fehlerbehebung).
  4. Wenn bei der Zuweisung aus einer Abfrage kein Wert zurückgegeben wird, weist SET NULL zu, wobei SELECT die Zuweisung überhaupt nicht vornimmt (sodass die Variable nicht von ihrem vorherigen Wert geändert wird).
  5. In Bezug auf Geschwindigkeitsunterschiede gibt es keine direkten Unterschiede zwischen SET und SELECT. Die Fähigkeit von SELECT, mehrere Aufgaben auf einmal zu erledigen, bietet jedoch einen leichten Geschwindigkeitsvorteil gegenüber SET.

3
Ich habe nicht abgelehnt, aber das Folgende ist nicht ganz richtig: "Was Geschwindigkeitsunterschiede betrifft - es gibt keine direkten Unterschiede zwischen SET und SELECT". Wenn Sie mehrere Werte in einem Slect zuweisen, kann dies viel schneller sein als über mehrere Sätze. Google up "Das Zuweisen mehrerer Variablen mit einem SELECT funktioniert schneller"
AK

14
@AlexKuznetsov: Der Satz danach sagt genau das.
OMG Ponys

3
@OMG Ponys: Es kann 10 mal schneller oder mehr sein, daher bin ich mir nicht sicher, ob es ein "leichter Geschwindigkeitsvorteil" ist.
AK

2
Insbesondere bei Verwendung einer While-Schleife habe ich RIESIGE Leistungssteigerungen festgestellt, indem ich alle meine Variablen mit One-Select vs. Many-Set gesetzt / neu initialisiert habe. Ich kann meine Variablenlogik auch in einer Auswahl konsolidieren, damit alle gleichzeitig ausgeführt werden: Beispiel: SELECT @Int = @Int + 1, @Int = @Int + 1Wenn sie @Intals 0 gestartet wird, endet sie als 2. Dies kann sehr nützlich sein, wenn aufeinanderfolgende Zeichenfolgenmanipulationen durchgeführt werden.
MikeTeeVee

Interessante Diskussion über Leistungsunterschiede. Wenn das Festlegen mehrerer Werte über select schneller ist (zum Codieren und Ausführen), besteht eine ausfallsichere Möglichkeit, Punkt 4 zu vermeiden (Ihr Variablenwert ändert sich nicht, wenn die Abfrage null zurückgibt) darin, Ihre Variable vor der Auswahl explizit auf null zu setzen. Wie vergleichen sich die beiden, wenn Sie dies berücksichtigen, hinsichtlich der Leistung? (Randnotiz: Ich verstehe die Gründe für die Auswahl, Ihre Variable nicht auf null zu setzen, falls eine Abfrage null zurückgibt. Wann würden Sie das jemals wollen?)
youcantryreachingme

155

Ich glaube, es SETist ANSI-Standard, während dies SELECTnicht der Fall ist. Beachten Sie auch das unterschiedliche Verhalten von SETvs. SELECTim folgenden Beispiel, wenn kein Wert gefunden wird.

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 Es ist besser, einmal zu laufen, um zu verstehen, zu überprüfen, zu spielen, sich das zu merken, um es nur zu lesen, aber andere Antworten sind nur Text
Gennady Vanin Геннадий Ванин

4
Wenn Sie tatsächlich verwendet haben select @var = (select name from master.sys.tables where name = 'qwerty'), würden Sie @var als null erhalten. Das Beispiel, das Sie geben, ist nicht dieselbe Abfrage.
Zack

4
Sie haben (select name from master.sys.tables where name = 'qwerty')für den einen und name from master.sys.tables where name = 'qwerty'für den anderen ... sehen Sie das nicht?
Zack

4
@Zack: Jedes ist die richtige Syntax für das, was ich zu testen versuche; Der Unterschied zwischen der Verwendung von SET und SELECT zum Zuweisen eines Werts zu einer Variablen, wenn die zugrunde liegende Abfrage keine Ergebnisse zurückgibt.
Joe Stefanelli

5
(select name from master.sys.tables where name = 'qwerty')ist eine skalare Unterabfrage und name from master.sys.tables where name = 'qwerty'eine einfache Abfrage. Die beiden unterschiedlichen Ausdrücke sollen nicht zu denselben Ergebnissen führen, obwohl Sie anscheinend implizieren, dass dies der Fall sein sollte. Wenn Sie das versuchen , zu sagen SETund SELECTSchlüsselwörter haben unterschiedliche Implementierungen, sollten Sie nicht verwenden zwei verschiedene Ausdrücke in Ihren Beispielen. msdn.microsoft.com/en-us/library/ms187330.aspx
Zack

27

Beim Schreiben von Abfragen sollte dieser Unterschied berücksichtigt werden:

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

sehr schön, prägnant
SimplyInk

8

Abgesehen von ANSI, Geschwindigkeit usw. gibt es einen sehr wichtigen Unterschied, der mir immer wichtig ist. mehr als ANSI und Geschwindigkeit. Die Anzahl der Fehler, die ich aufgrund dieses wichtigen Übersehens behoben habe, ist groß. Ich suche dies die ganze Zeit bei Codeüberprüfungen.

-- 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; 

Fast immer ist das nicht die Absicht des Entwicklers. Oben ist die Abfrage einfach, aber ich habe Abfragen gesehen, die ziemlich komplex sind und herauszufinden, ob sie einen einzelnen Wert zurückgeben oder nicht, ist nicht trivial. Die Abfrage ist häufig komplexer und hat zufällig einen einzelnen Wert zurückgegeben. Während der Entwicklertests ist alles in Ordnung. Dies ist jedoch wie eine tickende Bombe und führt zu Problemen, wenn die Abfrage mehrere Ergebnisse zurückgibt. Warum? Weil es der Variablen einfach den letzten Wert zuweist.

Versuchen wir jetzt dasselbe mit SET:

 -- Act
 set @employeeId = (select e.EmployeeId from dbo.Employee e);

Sie erhalten eine Fehlermeldung:

Die Unterabfrage gab mehr als 1 Wert zurück. Dies ist nicht zulässig, wenn die Unterabfrage folgt = ,! =, <, <=,>,> = Oder wenn die Unterabfrage als Ausdruck verwendet wird.

Das ist erstaunlich und sehr wichtig , denn warum sollte man etwas trivial „letztes Element in Folge“ , um die zugewiesen werden soll @employeeId. Mitselect Sie nie einen Fehler bekommen und Sie werden Minuten, Stunden mit dem Debuggen verbringen.

Möglicherweise suchen Sie nach einer einzelnen ID und SETwerden gezwungen, Ihre Abfrage zu korrigieren. So können Sie etwas tun wie:

-- Act
-- Notice the where clause
set @employeeId = (select e.EmployeeId from dbo.Employee e where e.EmployeeId = 1);
print @employeeId;

Aufräumen

drop table Employee;

Verwenden Sie abschließend:

  • SET: Wenn Sie einer Variablen einen einzelnen Wert zuweisen möchten und Ihre Variable für einen einzelnen Wert bestimmt ist.
  • SELECT: Wenn Sie einer Variablen mehrere Werte zuweisen möchten. Die Variable kann eine Tabelle, eine temporäre Tabelle oder eine Tabellenvariable usw. sein.
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.