USTAW kontra WYBÓR podczas przypisywania zmiennych?

Odpowiedzi:

412

Cytat , który podsumowuje z tego artykułu :

  1. SET jest standardem ANSI dla przypisywania zmiennych, SELECT nie.
  2. SET może przypisywać tylko jedną zmienną na raz, SELECT może wykonywać wiele przypisań jednocześnie.
  3. W przypadku przypisywania z zapytania SET może przypisać tylko wartość skalarną. Jeśli zapytanie zwróci wiele wartości / wierszy, wówczas SET spowoduje błąd. SELECT przypisze jedną z wartości do zmiennej i ukryje fakt, że zwrócono wiele wartości (więc prawdopodobnie nigdy nie dowiesz się, dlaczego coś poszło nie tak - baw się dobrze z rozwiązywaniem problemów)
  4. Przy przypisywaniu z zapytania, jeśli nie zostanie zwrócona żadna wartość, SET przypisze NULL, gdzie SELECT w ogóle nie wykona przypisania (więc zmienna nie zostanie zmieniona z poprzedniej wartości)
  5. Jeśli chodzi o różnice prędkości - nie ma bezpośrednich różnic między SET a SELECT. Jednak zdolność SELECT do wykonywania wielu zadań w jednym strzale daje mu niewielką przewagę prędkości nad SET.
Kucyki OMG
źródło
3
Nie przegłosowałem, ale poniższe stwierdzenie nie jest całkiem poprawne: „Jeśli chodzi o różnice prędkości - nie ma bezpośrednich różnic między SET a SELECT”. Jeśli przypiszesz wiele wartości w jednym zaznaczeniu, może to być znacznie szybsze niż w przypadku wielu zestawów. Google up „Przypisywanie wielu zmiennych za pomocą jednego SELECT działa szybciej”
AK
14
@AlexKuznetsov: Następnie zdanie mówi dokładnie to.
OMG Ponies
3
@OMG Kucyki: może być 10 razy szybszy lub więcej, więc nie jestem pewien, czy to „niewielka przewaga prędkości”.
AK
2
Zwłaszcza gdy korzystam z pętli While, zauważyłem OGROMNY wzrost wydajności poprzez ustawienie / ponowną inicjalizację wszystkich moich zmiennych za pomocą opcji One-Select vs. Many-Set. Mogę również skonsolidować moją Zmienną Logikę w Select, aby wszystkie działały jednocześnie: Przykład: SELECT @Int = @Int + 1, @Int = @Int + 1jeśli jest @Inturuchamiany jako 0, to kończy się na 2. Może to być bardzo przydatne podczas kolejnych operacji na łańcuchach.
MikeTeeVee
Interesująca dyskusja na temat różnicy wydajności. Jeśli ustawianie wielu wartości za pomocą select jest szybsze (do kodowania i wykonania), to jednym z bezpiecznych sposobów uniknięcia punktu 4 (wartość zmiennej nie zmienia się, jeśli zapytanie zwraca null) jest jawne ustawienie zmiennej na null przed wyborem. Jak to weźmiesz pod uwagę, w jaki sposób porównuje się je pod względem wydajności? (Uwaga dodatkowa: Nie rozumiem powodów, dla których select nie ustawia zmiennej na null w przypadku, gdy zapytanie zwraca null. Kiedy byś tego chciał?)
youcantryreachingme
155

Uważam, że SETjest to standard ANSI, a SELECTnie jest. Zwróć także uwagę na inne zachowanie SETvs. SELECTw poniższym przykładzie, gdy nie znaleziono wartości.

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' */
Joe Stefanelli
źródło
4
+1 Lepiej jest raz uruchomić, aby zrozumieć, sprawdzić, zagrać, zapamiętać, aby po prostu przeczytać, ale inne odpowiedzi to tylko tekst
Gennady Vanin Геннадий Ванин
4
Jeśli faktycznie użyłeś select @var = (select name from master.sys.tables where name = 'qwerty'), dostaniesz @var jako null. Podany przykład nie jest tym samym zapytaniem.
Zack
4
Masz (select name from master.sys.tables where name = 'qwerty')dla jednego, a name from master.sys.tables where name = 'qwerty'dla drugiego ... nie widzisz tego?
Zack
4
@Zack: Każda jest poprawną składnią tego, co próbuję zaprezentować; różnica między użyciem SET a SELECT do przypisania wartości zmiennej, gdy bazowe zapytanie nie zwraca żadnych wyników.
Joe Stefanelli
5
(select name from master.sys.tables where name = 'qwerty')jest skalarnym podzapytaniem i name from master.sys.tables where name = 'qwerty'jest prostym zapytaniem. Te dwa różne wyrażenia nie powinny dawać takich samych rezultatów, choć wydaje się, że sugerujesz, że powinny. Jeśli próbujesz powiedzieć, że słowa kluczowe SETi SELECTmają różne implementacje, nie powinieneś używać dwóch różnych wyrażeń w swoich przykładach. msdn.microsoft.com/en-us/library/ms187330.aspx
Zack
27

Pisząc zapytania, należy pamiętać o tej różnicy:

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*/
GorkemHalulu
źródło
bardzo ładne, zwięzłe
SimplyInk
8

Oprócz tego, że jest to ANSI i prędkość itp., Jest bardzo ważna różnica, która zawsze ma dla mnie znaczenie; więcej niż ANSI i prędkość. Liczba błędów, które usunąłem z powodu tego ważnego przeoczenia, jest duża. Cały czas szukam tego podczas przeglądów kodu.

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

Prawie zawsze nie tego chce deweloper. W powyższym zapytaniu jest proste, ale widziałem zapytania, które są dość złożone i ustalenie, czy zwróci jedną wartość, czy nie, nie jest banalne. Zapytanie jest często bardziej złożone i przez przypadek zwraca jedną wartość. Podczas testowania programistów wszystko jest w porządku. Ale to jest jak tykająca bomba i spowoduje problemy, gdy zapytanie zwróci wiele wyników. Czemu? Ponieważ po prostu przypisze ostatnią wartość do zmiennej.

Teraz spróbujmy tego samego z SET:

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

Otrzymasz błąd:

Subquery zwróciło więcej niż 1 wartość. Jest to niedozwolone, gdy podkwerenda występuje po =,! =, <, <=,>,> = Lub gdy podkwerenda jest używana jako wyrażenie.

To zadziwiające i bardzo ważne, ponieważ dlaczego chcesz przypisać trywialny „ostatni wynik w wyniku” do @employeeId. Dzięki selectniemu nigdy nie wystąpi żaden błąd i poświęcisz minuty, godziny debugowania.

Być może szukasz jednego identyfikatora i SETzmusisz Cię do naprawienia zapytania. Dlatego możesz zrobić coś takiego:

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

Sprzątać

drop table Employee;

Podsumowując, użyj:

  • SET: Gdy chcesz przypisać pojedynczą wartość do zmiennej, a twoja zmienna dotyczy jednej wartości.
  • SELECT: Gdy chcesz przypisać wiele wartości do zmiennej. Zmienna może być tabelą, tabelą temperatur lub zmienną tabelową itp.
Kodowanie Yoshi
źródło