SELECT INTOは、実行前にTempDBで#Object名を予約しますか?


8

デバッグに役立つQuickieプロシージャをまとめると、コンパイラでエラーのように見えるものに遭遇しました。

create proc spFoo
    @param bit
as
begin
    if @param = 0
    begin 
        select * 
        into #bar
        from [master].dbo.spt_values
        -- where number between ...
    end
    else
    begin
        select top 10 * 
        into #bar
        from [master].dbo.spt_values
        order by newid();
    end;
end;

上記を試行すると、次のエラーが返されます

メッセージ2714、レベル16、状態1、プロシージャspFoo、行19
データベースにはすでに「#bar」という名前のオブジェクトがあります。

人間が読める意味では、プロシージャは問題ないように見えます。ブロックselect into内にラップされているため、実行されるステートメントは1つだけですif-else。ただし、SQLサーバーは、ステートメントが互いに論理的に除外されていることを確認できません。おそらくもっと混乱するのdrop table #fooは、以下のようにがif-elseブロック内に配置されたときにエラーが残ることです(これにより、オブジェクト名の割り当てを解除するようコンパイラーに指示すると想定されます)。

create proc spFoo
    @param bit
as
begin
    select top 1 * 
    into #bar
    from [master].dbo.spt_values

    if @param = 0
    begin 
        drop table #bar;

        select * 
        into #bar
        from [master].dbo.spt_values
        -- where number between ...
    end
    else
    begin
        drop table #bar;

        select top 10 * 
        into #bar
        from [master].dbo.spt_values
        order by newid();
    end;
end;

プロシージャ自体は問題ありません。私はそれを吸い上げてcreate table #foo( ... )and insert #foo ( ... )ステートメントを書きました、私はselect * into 構文でスキップしようとしていました。この時点で、私はコンパイラがレイジーガイ構文でなぜ私に打ちのめされたのかを理解しようとしているだけです。私が考えることができる唯一のことは、DDLコマンドがオブジェクト名IN TEMPDBを予約することです。

なぜ太字のテキストなのですか?

create proc spIck
as
begin
    create table #ack ( col1 int );
    drop table #ack;
    create table #ack ( colA char( 1 ) );
    drop table #ack;
end;

これは、上記と同じエラーコードで失敗します。しかし、次の...

create proc spIck
as
begin
    create table ack ( col1 int );
    drop table ack;
    create table ack ( colA char( 1 ) );
    drop table ack;
end;

...成功します。上記の元のprocの試行と同じです。そう...

私の質問はこれです

TempDBユーザーデータベースとは対照的に、オブジェクトのオブジェクト名予約の違いは何ですか(なぜ存在するのですか)。私が検討した論理クエリ処理のリファレンスもDDLコマンドのリファレンスも、これを説明しているようには見えません。


1
「SQL Serverストアドプロシージャ、XML、およびHTMLのグルのガイド」からのこのスクリーンショット(Googleブックス)は関連性があり、これが7.0以降の動作方法であることを示しています。i.stack.imgur.com/8pDGT.png
Martin Smith

6ページのようです(後でスレッドにアクセスする人のために参考にしてください)。
Peter Vandivier、2016

回答:


6

これは、TempDBでのオブジェクト名の予約や、ランタイムとは何の関係もありません。これは単に、パーサーがロジックまたはコードのパスをたどることができず、コードがそのテーブルを2回作成できない可能性があることを保証します。[解析]ボタン(Ctrl+ F5)をクリックするだけで、まったく同じ(非実行時!)エラーが発生することに注意してください。基本的に、これがある場合:

IF 1=1 
  CREATE TABLE #foo(id1 INT);
ELSE
  CREATE TABLE #foo(id2 INT);

パーサーはこれを見ます:

  CREATE TABLE #foo(id1 INT);
  CREATE TABLE #foo(id2 INT);

TempDBで作成された実際のユーザーテーブルを含む実際のテーブルでは、なぜこのように機能しないのですか(データベース固有でもないことに注意してください)。私が提案できる唯一の答えは、パーサーには#tempテーブルのルールのセットが異なるということです(他にも多くの違いがあります)。より具体的な理由が必要な場合は、Microsoftでケースを開いて、詳細が提供されるかどうかを確認する必要があります。私の推測では、「これが動作する方法です」と言われるでしょう。

これらの回答のいくつかの詳細:


実際、「これが機能する方法」はまさに彼らの反応です。まあ...
ピーターヴァンディヴィエ2016年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.