T-SQLで変数を代入するときのSET
ステートメントとSELECT
ステートメントの違いは何ですか?
- SETは変数割り当てのANSI標準ですが、SELECTはそうではありません。
- SETは一度に1つの変数しか代入できませんが、SELECTは一度に複数の代入を行うことができます。
- クエリから代入する場合、SETはスカラ値しか代入できません。クエリが複数の値/行を返す場合、SETはエラーを発生させます。 SELECTは変数の1つを変数に代入し、複数の値が返されたという事実を隠します(したがって、他の場所で問題が発生した理由を知ることはおそらくないでしょう。
- 値が返されない場合にクエリから代入すると、SETはNULLを代入します。SELECTは代入をまったく行いません(したがって、変数は以前の値から変更されません)。
- 速度の違いに関しては - SETとSELECTの間に直接の違いはありません。ただし、一度に複数の代入を行うSELECTの機能は、SETよりもわずかに速度が向上します。
私は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' */
クエリを書くとき、この違いを覚えておくべきです:
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);
エラーが発生します。
副照会が複数の値を戻しました。副照会が=、!=、<、<=、>、> =の後に続く場合、または副照会が式として使用される場合、これは許可されません。
なぜあなたは些細な "結果の最後の項目"を@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
:変数に複数の値を代入したい場合。変数は、テーブル、一時テーブル、テーブル変数などです。