web-dev-qa-db-ja.com

選択結果を変数に割り当てる方法

選択したフィールド値をクエリから変数に保存し、更新ステートメントで使用するにはどうすればよいですか?

私の手順は次のとおりです。

次のことを行うSQL Server 2005 T-SQLストアドプロシージャを作成しています。

  1. 請求書テーブルから請求書IDのリストを取得し、カーソルに保存します
  2. カーソルから請求書IDを取得-> tmp_key変数
  3. foreach tmp_keyは、顧客テーブルから請求書クライアントのプライマリ連絡先IDを見つけます
  4. クライアントの連絡先キーをプライマリ連絡先IDで更新します
  5. カーソルを閉じる

ここに私のコードがあります:

DECLARE @tmp_key int
DECLARE @get_invckey cursor 

set @get_invckey = CURSOR FOR 
    select invckey from tarinvoice where confirmtocntctkey is null and tranno like '%115876'

OPEN @get_invckey 

FETCH NEXT FROM @get_invckey into @tmp_key

WHILE (@@FETCH_STATUS = 0) 
BEGIN 
    SELECT c.PrimaryCntctKey as PrimaryContactKey
    from tarcustomer c, tarinvoice i
    where i.custkey = c.custkey and i.invckey = @tmp_key

    UPDATE tarinvoice set confirmtocntctkey = PrimaryContactKey where invckey = @tmp_key
    FETCH NEXT FROM @get_invckey INTO @tmp_key
END 

CLOSE @get_invckey
DEALLOCATE @get_invckey

PrimaryContactKeyを保存し、次の更新ステートメントのset句で再度使用するにはどうすればよいですか?カーソル変数を作成するのですか、それともint型の別のローカル変数を作成するのですか?

70
phill
DECLARE @tmp_key int
DECLARE @get_invckey cursor 

SET @get_invckey = CURSOR FOR 
    SELECT invckey FROM tarinvoice WHERE confirmtocntctkey IS NULL AND tranno LIKE '%115876'

OPEN @get_invckey 

FETCH NEXT FROM @get_invckey INTO @tmp_key

DECLARE @PrimaryContactKey int --or whatever datatype it is

WHILE (@@FETCH_STATUS = 0) 
BEGIN 
    SELECT @PrimaryContactKey=c.PrimaryCntctKey
    FROM tarcustomer c, tarinvoice i
    WHERE i.custkey = c.custkey AND i.invckey = @tmp_key

    UPDATE tarinvoice SET confirmtocntctkey = @PrimaryContactKey WHERE invckey = @tmp_key
    FETCH NEXT FROM @get_invckey INTO @tmp_key
END 

CLOSE @get_invckey
DEALLOCATE @get_invckey

編集:
この質問は、私が予想していたよりもはるかに多くの関心を集めています。回答でカーソルを使用することを推奨しているのではなく、質問に基づいて値を割り当てる方法を示していることに注意してください。

44
squillman

私はちょうど同じ問題を抱えていました...

declare @userId uniqueidentifier
set @userId = (select top 1 UserId from aspnet_Users)

またはさらに短い:

declare @userId uniqueidentifier
SELECT TOP 1 @userId = UserId FROM aspnet_Users
92
Pawel G.

これを試して

SELECT @PrimaryContactKey = c.PrimaryCntctKey
FROM tarcustomer c, tarinvoice i
WHERE i.custkey = c.custkey 
    AND i.invckey = @tmp_key

UPDATE tarinvoice SET confirmtocntctkey = @PrimaryContactKey 
WHERE invckey = @tmp_key
FETCH NEXT FROM @get_invckey INTO @tmp_key

この変数は、ループの外側で標準のTSQL変数として宣言します。

また、これは、カーソルを処理するときだけでなく、変数へのあらゆるタイプの選択に対してこれを行う方法であることに注意する必要があります。

19
TheTXI

なぜカーソルが必要なのですか?コードのセグメント全体をこれに置き換えることができます。これにより、多数の行ではるかに高速に実行されます。

UPDATE tarinvoice set confirmtocntctkey = PrimaryCntctKey 
FROM tarinvoice INNER JOIN tarcustomer ON tarinvoice.custkey = tarcustomer.custkey
WHERE confirmtocntctkey is null and tranno like '%115876'
14
GilaMonster

変数を安全に割り当てるには、SET-SELECTステートメントを使用する必要があります。

SET @PrimaryContactKey = (SELECT c.PrimaryCntctKey
    FROM tarcustomer c, tarinvoice i
    WHERE i.custkey = c.custkey 
    AND i.invckey = @tmp_key)

開始括弧と終了括弧の両方があることを確認してください!

SET-SELECTバージョンが変数を設定する最も安全な方法である理由は2つあります。

1。 SELECTはいくつかの投稿を返します

次の選択の結果、複数の投稿が発生した場合はどうなりますか?

SELECT @PrimaryContactKey = c.PrimaryCntctKey
FROM tarcustomer c, tarinvoice i
WHERE i.custkey = c.custkey 
    AND i.invckey = @tmp_key

@PrimaryContactKeyには、結果のlast postの値が割り当てられます。

実際、@PrimaryContactKeyには結果の投稿ごとに1つの値が割り当てられるため、結果としてSELECTコマンドが処理していた最後の投稿の値が含まれます。

どのポストが「最後」であるかは、クラスター化インデックスによって決定されます。クラスター化インデックスが使用されていない場合、または主キーがクラスター化されている場合、「最後」のポストは最後に追加されたポストになります。この動作は、最悪の場合、テーブルのインデックスが変更されるたびに変更される可能性があります。

SET-SELECTステートメントを使用すると、変数はnullに設定されます。

2。 SELECTは投稿を返しません

選択が結果をまったく返さない場合、コードの2番目のバージョンを使用するとどうなりますか?

変数の値がnullにならないと思われるものとは反対に-以前の値を保持します

これは、上記のように、SQLが投稿ごとに変数に値を割り当てるためです-結果に投稿が含まれていない場合、変数を使用して何もしません。したがって、変数は、ステートメントを実行する前の値のままです。

SET-SELECTステートメントを使用すると、値はnullになります。

参照: 変数を割り当てるときのSETとSELECTの違い?

11
Erk