変数を割り当てるときのSETとSELECT?


回答:


411

この記事の要約である引用

  1. SETは変数代入のANSI標準ですが、SELECTはそうではありません。
  2. SETは一度に1つの変数のみを割り当てることができ、SELECTは一度に複数の割り当てを行うことができます。
  3. クエリから割り当てる場合、SETはスカラー値のみを割り当てることができます。クエリが複数の値/行を返す場合、SETはエラーを発生させます。SELECTは値の1つを変数に割り当て、複数の値が返されたという事実を隠します(そのため、他の場所で問題が発生した理由がわからない可能性があります。そのトラブルシューティングを楽しんでください)。
  4. クエリから代入するときに値が返されない場合、SETはNULLを代入します。SELECTは代入をまったく行いません(そのため、変数は以前の値から変更されません)。
  5. 速度の違いに関する限り-SETとSELECTの間に直接的な違いはありません。ただし、1つのショットで複数の割り当てを行うSELECTの機能は、SETよりも速度がわずかに優れています。

3
私は反対票を投じませんでしたが、「速度の違いに関する限り-SETとSELECTの間に直接の違いはありません」は正しくありません。1つのセレクションに複数の値を割り当てると、マルチプルセットを使用するよりもはるかに高速になります。グーグルアップ "1つのSELECTで複数の変数を割り当てるとより速く機能する"
AK

14
@AlexKuznetsov:その後の文章はそれを正確に述べています。
OMGポニー

3
@OMGポニー:10倍以上高速になる可能性があるため、「わずかな速度の利点」かどうかはわかりません。
AK

2
特に、While-Loopを使用している場合、one-Selectとmany-Setを使用してすべての変数を設定/再初期化すると、パフォーマンスが大幅に向上します。変数ロジックを選択で統合して、すべてを一度に実行することもできます。例:SELECT @Int = @Int + 1, @Int = @Int + 1@Int0から開始すると、2で終了します。これは、連続する文字列操作を行うときに非常に役立ちます。
MikeTeeVee 2015

パフォーマンスの違いに関する興味深い議論。selectを使用して複数の値を設定する方が速い(コード化して実行する)場合、ポイント4(クエリがnullを返した場合に変数値が変更されない)を回避するためのフェイルセーフな方法は、selectの前に変数を明示的にnullに設定することです。それを考慮に入れたら、2つはどのようにパフォーマンスを比較しますか?(補足:クエリがnullを返した場合にselectが変数をnullに設定しない理由は理解できません。いつそれが必要ですか?)
youcantryreachingme

155

SETはANSI標準だと思いますが、そうでSELECTはありません。また、値が見つからない場合の以下の例のSETvs. の異なる動作にも注意してください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理解、確認、再生、記憶するために1回実行することをお
勧めし

4
実際に使用したselect @var = (select name from master.sys.tables where name = 'qwerty')場合、@ varはnullになります。あなたが与えている例は同じクエリではありません。
Zack

4
あなたは(select name from master.sys.tables where name = 'qwerty')一つのために、そしてもう一つのname from master.sys.tables where name = 'qwerty'ために...あなたはそれを見ませんか?
Zack

4
@Zack:それぞれが、私がデモしようとしているものの正しい構文です。基になるクエリが結果を返さない場合に、SETとSELECTを使用して変数に値を割り当てる方法の違い。
Joe

5
(select name from master.sys.tables where name = 'qwerty')スカラーサブクエリでありname from master.sys.tables where name = 'qwerty'、単純なクエリです。2つの異なるが同じ結果を生成することは想定されていませんが、そうする必要があることを示唆しているようです。あなたが言おうとしている場合SETSELECT、キーワードが異なる実装を持って、次の2つの異なる使用すべきでない表現を、あなたの例で。msdn.microsoft.com/en-us/library/ms187330.aspx
Zack

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

エラーが表示されます。

サブクエリが複数の値を返しました。これは、サブクエリが=、!=、<、<=、>、> =の後に続く場合、またはサブクエリが式として使用される場合は許可されません。

これは驚くべきことであり、非常に重要です。なぜなら、些細な「結果の最後の項目」をに割り当てたいのはなぜですか@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:複数の値を変数に割り当てたい場合。変数は、テーブル、一時テーブル、テーブル変数などです。
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.