Каковы различия между операторами SET
и SELECT
при назначении переменных в T-SQL?
SET или SELECT при назначении переменных?
Ответ 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
: когда вы хотите назначить несколько значений переменной. Переменная может быть таблицей, временной таблицей или табличной переменной и т.д.