Відповіді:
Цитата , яка узагальнює цю статтю :
- SET - стандарт ANSI для призначення змінної, SELECT - ні.
- SET може призначати одночасно одну змінну, SELECT може робити декілька призначень одночасно.
- Якщо призначити за запитом, SET може призначити лише скалярне значення. Якщо запит повертає кілька значень / рядків, то SET викликає помилку. SELECT призначить одне зі значень змінній та приховає факт повернення кількох значень (так що ви, ймовірно, ніколи не дізнаєтесь, чому щось інакше піде не так - отримайте задоволення від усунення несправностей із цим)
- При призначенні запиту, якщо значення не повернуто, SET призначить NULL, де SELECT взагалі не зробить призначення (тому змінна не буде змінена зі свого попереднього значення)
- Що стосується різниці швидкостей - прямих відмінностей між SET і SELECT немає. Однак здатність SELECT робити кілька завдань за один кадр дає незначну перевагу в швидкості порівняно з SET.
SELECT @Int = @Int + 1, @Int = @Int + 1
якщо @Int
запустити як 0, то він закінчується як 2. Це може бути дуже корисним під час послідовних маніпуляцій з рядками.
Я вважаю, що 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' */
select @var = (select name from master.sys.tables where name = 'qwerty')
ви отримали б @var як null. Приклад, який ви наводите, - це не той самий запит.
(select name from master.sys.tables where name = 'qwerty')
для одного, а name from master.sys.tables where name = 'qwerty'
для іншого ... ви цього не бачите?
(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
Під час написання запитів слід пам’ятати про цю різницю:
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*/
Окрім того, що одна 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
: Коли ви хочете призначити змінній кілька значень. Змінна може бути таблицею, тимчасовою таблицею або змінною таблиці тощо.