SET проти SELECT при призначенні змінних?


Відповіді:


412

Цитата , яка узагальнює цю статтю :

  1. SET - стандарт ANSI для призначення змінної, SELECT - ні.
  2. SET може призначати одночасно одну змінну, SELECT може робити декілька призначень одночасно.
  3. Якщо призначити за запитом, SET може призначити лише скалярне значення. Якщо запит повертає кілька значень / рядків, то SET викликає помилку. SELECT призначить одне зі значень змінній та приховає факт повернення кількох значень (так що ви, ймовірно, ніколи не дізнаєтесь, чому щось інакше піде не так - отримайте задоволення від усунення несправностей із цим)
  4. При призначенні запиту, якщо значення не повернуто, SET призначить NULL, де SELECT взагалі не зробить призначення (тому змінна не буде змінена зі свого попереднього значення)
  5. Що стосується різниці швидкостей - прямих відмінностей між SET і SELECT немає. Однак здатність SELECT робити кілька завдань за один кадр дає незначну перевагу в швидкості порівняно з SET.

3
Я не заперечував, але наступне не зовсім коректно: "Що стосується різниці швидкостей - прямих відмінностей між SET і SELECT немає". Якщо ви призначите кілька значень за один вибір, це може бути набагато швидше, ніж через множинні множини. Google up "Призначення декількох змінних одним SELECT працює швидше"
АК

14
@AlexKuznetsov: Після цього речення говорить саме це.
OMG Ponies

3
@OMG Поні: Це може бути в 10 разів швидше або більше, тому я не впевнений, що це "незначна перевага в швидкості".
АК

2
Особливо під час використання циклу while-Loop я бачив величезні показники підвищення продуктивності, встановлюючи / повторно ініціалізуючи всі мої змінні, використовуючи один-Select vs. many-Set's. Я також можу консолідувати мінливу мінливу в «Вибір» для того, щоб запустити все одночасно: Приклад: SELECT @Int = @Int + 1, @Int = @Int + 1якщо @Intзапустити як 0, то він закінчується як 2. Це може бути дуже корисним під час послідовних маніпуляцій з рядками.
MikeTeeVee

Цікава дискусія про різницю у виконанні. Якщо встановлення декількох значень через select є швидшим (кодувати та виконувати), тоді один недостовірний спосіб уникнути пункту 4 (значення змінної не змінюється, якщо запит повертає нуль) - це явно встановити свою змінну до нуля до вибору. Як тільки ви визначите це, як вони порівнюють ефективність? (Побічна примітка: я не розумію обґрунтування вибору не встановлення вашої змінної до нуля, якщо запит повертає нуль. Коли ви коли-небудь цього хочете?)
youcantryreachingme

155

Я вважаю, що SETце стандарт ANSI, тоді як SELECTце не так. Також врахуйте різну поведінку SETпорівняно SELECTз наведеним нижче прикладом, коли значення не знайдено.

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 Краще запустити один раз, щоб зрозуміти, перевірити, грати, запам’ятати, що просто читати, але інші відповіді - це лише текст
Геннадій Ванін Геннадій Ванін

4
Якщо ви насправді використовували, select @var = (select name from master.sys.tables where name = 'qwerty')ви отримали б @var як null. Приклад, який ви наводите, - це не той самий запит.
Зак

4
У вас є (select name from master.sys.tables where name = 'qwerty')для одного, а name from master.sys.tables where name = 'qwerty'для іншого ... ви цього не бачите?
Зак

4
@Zack: Кожен є правильним синтаксисом для того, що я намагаюся демонструвати; різниця між використанням SET проти SELECT для призначення значення змінній, коли базовий запит не повертає результатів.
Джо Стефанеллі

5
(select name from master.sys.tables where name = 'qwerty')є скалярним підпитом і name from master.sys.tables where name = 'qwerty'є простим запитом. Два різних вирази не повинні давати однакових результатів, хоча, мабуть, ви маєте на увазі, що вони повинні. Якщо ви намагаєтеся сказати, що ключові слова SETта SELECTключові слова мають різні реалізації, вам не слід використовувати два різних вирази у своїх прикладах. msdn.microsoft.com/en-us/library/ms187330.aspx
Зак

27

Під час написання запитів слід пам’ятати про цю різницю:

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

дуже приємно, лаконічно
SimplyInk

8

Окрім того, що одна ANSI та швидкість тощо, є дуже важлива різниця, яка завжди має для мене значення; більше, ніж ANSI та швидкість. Кількість помилок, які я виправила завдяки цьому важливому огляду, велика. Я шукаю це під час огляду коду весь час.

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

Майже завжди, це не те, що розробник має намір. У вищесказаному запит прямо вперед, але я бачив запити, які є досить складними, і з'ясування того, поверне він єдине значення чи ні, не є тривіальним. Запит часто складніший за цей, і випадково він повертає єдине значення. Під час тестування розробника все добре. Але це схоже на тикаючу бомбу і викличе проблеми, коли запит поверне кілька результатів. Чому? Тому що він просто призначить останню величину змінній.

Тепер спробуємо те ж саме з SET:

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

Ви отримаєте помилку:

Підзапит повернув більше 1 значення. Це заборонено, коли підзапит слід =,! =, <, <=,>,> = Або коли підзапит використовується як вираз.

Це дивовижно і дуже важливо, тому що чому ви хочете призначити якийсь тривіальний "останній результат в результаті" @employeeId. З selectвами ніколи не вийде жодної помилки, і ви витратите хвилини, години налагодження.

Можливо, ви шукаєте єдиний Id і SETзмусить вас виправити запит. Таким чином, ви можете зробити щось на кшталт:

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

Прибирати

drop table Employee;

На закінчення використовуйте:

  • SET: Коли ви хочете призначити одне значення змінній, а ваша змінна - для одного значення.
  • SELECT: Коли ви хочете призначити змінній кілька значень. Змінна може бути таблицею, тимчасовою таблицею або змінною таблиці тощо.
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.