T-SQLのテーブル変数にSELECT INTO


372

複雑なSELECTクエリを取得しました。そこからすべての行をテーブル変数に挿入したいのですが、T-SQLでは許可されていません。

同じように、SELECT INTOまたはINSERT EXECクエリでテーブル変数を使用することはできません。 http://odetocode.com/Articles/365.aspx

短い例:

declare @userData TABLE(
                        name varchar(30) NOT NULL,
                        oldlocation varchar(30) NOT NULL
                       )

SELECT name, location
INTO @userData
FROM myTable
    INNER JOIN otherTable ON ...
WHERE age > 30

table変数のデータは、後で別のテーブルに挿入/更新するために使用されます(ほとんどの場合、マイナーな更新を使用した同じデータのコピー)。これの目標はSELECT INTO、適切なテーブルに直接アクセスするよりも、スクリプトを少し読みやすく、カスタマイズしやすくすることです。rowcountはかなり小さいため、パフォーマンスは問題にならず、必要な場合にのみ手動で実行されます。
...または私がすべて間違っているかどうかを教えてください。

回答:


601

次のようなものを試してください:

DECLARE @userData TABLE(
    name varchar(30) NOT NULL,
    oldlocation varchar(30) NOT NULL
);

INSERT INTO @userData (name, oldlocation)
SELECT name, location FROM myTable
INNER JOIN otherTable ON ...
WHERE age > 30;

2
"SELECT name、location FROM myTable"をUserDataテーブルに挿入する値として使用する場合、selectの変数の名前がテーブル定義の名前と一致しているかどうかは関係ありません。'name'を選択してUserData 'name'変数に移動していますが、 'location'を選択して、なんとかしてそれをUserData 'oldlocation'変数に割り当てています。SQLはこれらを自動的にマッピングするだけですか、それとも何らかの例外をスローしますか?
Aran Mulholland 2015年

名前は問題ではなく、列のタイプのみです。
CristiC 2015年

5
うわー、それは理にかなっていますが、同時に私のパーサーは一種の気分を害しているように感じます:)
Aran Mulholland

これをUPDATEステートメントで使用できないようです:
gist

1
insertステートメントでは、列を明示的に宣言しない場合、select *と同様に、元のcreate tableステートメントで宣言された順にマップされます。したがって、selectステートメントの場所は@userDataテーブルのoldlocationにマップされます。これは、場所がselectの結果セットの位置2にあり、oldlocationがテーブル定義の列2であるためです。とはいえ、これを行うことはありません。列または行のデータベースの順序に依存しないでください。これについては常に明確にしてください。
アブスミス2017

94

の目的SELECT INTOは(ドキュメントごとに、私の強調)

別のテーブルの値から新しいテーブルを作成するに

しかし、あなたはすでに持っているターゲット表を!だからあなたが欲しいのは

INSERT文は、テーブルに1つ以上の新しい行を追加します

次の方法でデータ値を指定できます。

...

SELECTサブクエリを使用して、次のような1つ以上の行のデータ値を指定します。

  INSERT INTO MyTable 
 (PriKey, Description)
        SELECT ForeignKey, Description
        FROM SomeView

そして、この構文ではMyTable、テーブル変数であることを許可されています。


1
受け入れられた回答にこの情報が含まれていることを本当に願っています!
Davie Brown、

MyTableがこれを行うと「無効なオブジェクト名」になるので、この回答に欠けているものがあります。
マイクフリン

@MikeFlynnはMyTableここにあるプレースホルダーの名前のあなたの実際のテーブルMyTable... という名前のテーブルを持つ実際のデータベースはないと思います
AakashM

また、SELECT INTOを使用してテーブル変数を作成または宣言したい場合...?たとえば、テーブル変数の列をt1.somecolumn、t1.othercolumn、t2。*として定義するには
Armando

27

共通のテーブル式を使用して一時データセットを保存することもできます。彼らはよりエレガントでアドホックフレンドリーです:

WITH userData (name, oldlocation)
AS
(
  SELECT name, location 
  FROM   myTable    INNER JOIN 
         otherTable ON ...
  WHERE  age>30
)
SELECT * 
FROM   userData -- you can also reuse the recordset in subqueries and joins

これが大好き!ありがとうございました。
fourpastmidnight

これはコピーを作成しないと思います。userDataから削除または更新した場合、元のテーブルのレコードは削除および更新されませんか?
atreeon

長いCTEを使用して複数のテーブルを参照していないとしてなど、労働組合に加入するようはい、DELETEおよびCTEのUPDATEは、ソーステーブルを変更します
nanestev

2
これの欠点は、直後のコマンドでのみCTEテーブルを使用できることです。何らかの理由で結果セットを複数回通過させる必要がある場合、CTEは機能しません。OPは、複数の変更が行われることを示唆しているようです。その場合、これは機能しません-「テーブル変数のデータは、後で別のテーブルに挿入/更新するために使用されます(ほとんど同じデータのマイナーなコピー)アップデート)。」
Tony

16

アプリケーションから実行していない場合は、一時テーブルを使用してみてください。(これを手動で実行してもかまいません)

SELECT name, location INTO #userData FROM myTable
INNER JOIN otherTable ON ...
WHERE age>30

テーブルをそのように宣言する作業をスキップします...アドホッククエリに役立ちます...これにより、同じ一時セッションでない限り、他のセッションからは見えないローカル一時テーブルが作成されます。アプリからクエリを実行している場合、おそらく問題があります。

アプリで実行する必要がある場合は、次のように宣言された変数を使用します。

DECLARE @userData TABLE(
    name varchar(30) NOT NULL,
    oldlocation varchar(30) NOT NULL
);

INSERT INTO @userData
SELECT name, location FROM myTable
INNER JOIN otherTable ON ...
WHERE age > 30;

編集:多くの人が接続からセッションへの更新された可視性について述べたように。セッションは再利用できるため、一時テーブルの作成はWebアプリケーションのオプションではありません。これらの場合は一時変数に固執してください。


2
申し訳ありませんが、私にはCREATE TABLEの権限がないことを忘れていました。
インドレック

6
一時ファイルを作成すると、オーバーヘッドが少し増えます。
パパラッツォ

2
一時テーブルの使用は常に安全であるとは限りません。たとえば、Webサービス。サーバー上の最大接続を制限し、SQLをもう少し保護する単一接続のWebサービスを使用すると、通過するすべてのクエリに対して一時テーブルが存在し、現在使用しているユーザーを上書きできます。
フランク2014年

12
@Franck-グローバル一時テーブル(2つのハッシュプレフィックス)を使用している場合は正しいです。ただし、ローカル一時テーブル(ハッシュプレフィックス1つ)は単一セッション(別名単一接続)に分離されるため、すべてのリクエストに単一接続を使用している場合を除いて、同時並行性の問題はありません(助言された)。ただし、パフォーマンスへの影響の可能性は残ります。
maf748 2014年

@GazB確かに、副作用のあるステートメントはでの使用から除外されますfunction。私の経験では、誰かがそのようなステートメントを必要としていると考えるほとんどの場合、これは実際に彼らが自分自身を再考するfunctionか、少なくともにリファクタリングする必要があることを意味しprocedureます。少なくとも自分のために言えば。:-)
underscore_d


5

最初に一時テーブルを作成します。

ステップ1:

create table #tblOm_Temp (

    Name varchar(100),
    Age Int ,
    RollNumber bigint
)

**ステップ2:** Tempテーブルに値を挿入します。

insert into #tblom_temp values('Om Pandey',102,1347)

手順3:一時テーブルのデータを保持するテーブル変数を宣言します。

declare   @tblOm_Variable table(

    Name Varchar(100),
    Age int,
    RollNumber bigint
)

手順4:一時テーブルから値を選択し、テーブル変数に挿入します。

insert into @tblOm_Variable select * from #tblom_temp

最後に、一時テーブルからテーブル変数に値が挿入されます

ステップ5:テーブル変数に挿入された値を確認できます。

select * from @tblOm_Variable

1

OK、これで十分な労力で、以下を使用して@tableに挿入できます:

INSERT @TempWithheldTable SELECT
a.SuspendedReason、a.SuspendedNotes、a.SuspendedBy、a.ReasonCode FROM OPENROWSET(BULK 'C:\ DataBases \ WithHeld.csv'、FORMATFILE = N'C:\ DataBases \ Format.txt '、
ERRORFILE = N'C:\ Temp \ MovieLensRatings.txt ')AS a;

ここでの主なことは、挿入する列を選択することです。


「テーブル変数 "@TempWithheldTable"を宣言する必要があります」というコンパイルエラーメッセージが表示される
atreeon

-5

SELECT INTOを使用する1つの理由は、IDENTITYを使用できることです。

SELECT IDENTITY(INT,1,1) AS Id, name
INTO #MyTable 
FROM (SELECT name FROM AnotherTable) AS t

これはテーブル変数では機能しません。これは残念です...


6
IDENTITYただし、列を使用してテーブル変数を宣言できます。
マーティン・スミス
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.