SET или SELECT при назначении переменных?

Каковы различия между операторами SET и SELECT при назначении переменных в T-SQL?

Ответ 1

Quote, в котором суммируется в этой статье:

  • SET - стандарт ANSI для назначения переменных, SELECT - нет.
  • SET может назначать только одну переменную за один раз, SELECT может выполнять сразу несколько присваиваний.
  • При назначении из запроса SET может назначать только скалярное значение. Если запрос возвращает несколько значений/строк, то SET вызывает ошибку. SELECT назначит одно из значений переменной и скроет тот факт, что были возвращены несколько значений (так что вы, вероятно, никогда не узнаете, почему что-то пошло не так в другом месте) получайте удовольствие от устранения неполадок в этом)
  • При назначении из запроса, если нет возвращаемого значения, SET назначит NULL, где SELECT не будет выполнять назначение вообще (поэтому переменная не будет изменена с ее предыдущего значения)
  • Что касается разности скоростей - прямых и прямых между установками и SELECT нет. Однако способность SELECT выполнять несколько присвоений одним выстрелом дает ему небольшое преимущество по сравнению с SET.

Ответ 2

Я считаю, что SET является стандартом ANSI, а SELECT - нет. Также обратите внимание на различное поведение SET vs. 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' */

Ответ 3

При написании запросов эту разницу следует учитывать:

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

Ответ 4

Помимо 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 вы никогда не получите никаких ошибок и потратите минуты, часы на отладку.

Возможно, вы ищете один идентификатор, и 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: когда вы хотите назначить несколько значений переменной. Переменная может быть таблицей, временной таблицей или табличной переменной и т.д.