Apakah SELECT INTO Cadangan Nama #Object di TempDB Sebelum Runtime?

8

Menyatukan quickie proc untuk membantu debugging, saya menemukan apa yang tampaknya merupakan kesalahan dalam kompiler.

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;

Mencoba di atas mengembalikan kesalahan berikut

Msg 2714, Level 16, Negara 1, Prosedur spFoo, Baris 19
Sudah ada objek bernama '#bar' dalam database.

Dalam arti yang dapat dibaca manusia, proc tampaknya baik-baik saja: hanya satu select intopernyataan yang akan dieksekusi karena mereka dibungkus di dalam if-elseblok. Sangat baik, SQL server tidak dapat mengkonfirmasi bahwa pernyataan secara logis dikecualikan dari satu sama lain. Mungkin yang lebih membingungkan adalah bahwa kesalahan tetap ketika drop table #fooditempatkan di dalam blok if-else (yang diasumsikan akan memberitahu kompiler untuk membatalkan alokasi nama objek) seperti di bawah ini.

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;

Proc itu sendiri baik-baik saja. Saya mengisapnya dan menulis create table #foo( ... )dan insert #foo ( ... )pernyataan, saya sudah mencoba untuk melewatkan dengan select * into sintaks. Pada titik ini, saya hanya mencoba untuk memahami mengapa kompiler mencampuri saya dengan sintaks malas-guy. Satu-satunya hal yang dapat saya pikirkan adalah bahwa perintah DDL menyimpan nama objek DI TEMPDB .

Mengapa teksnya tebal?

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

Ini gagal dengan kode kesalahan yang sama seperti di atas. Namun berikut ini ...

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

... berhasil. Hal yang sama mengikuti di atas untuk upaya proc asli. Begitu...

Pertanyaan saya adalah ini

Apa perbedaannya (dan mengapa itu ada) dalam reservasi nama objek untuk TempDBobjek yang bertentangan dengan database pengguna. Tidak satu pun dari referensi Pemrosesan Permintaan Logika atau referensi perintah DDL yang telah saya ulas tampaknya menjelaskan hal ini.

Peter Vandivier
sumber
1
Tangkapan layar ini dari "Panduan Guru untuk Prosedur yang Disimpan SQL Server, XML, dan HTML" (di Google Buku) tampaknya relevan dan menunjukkan ini telah menjadi cara kerjanya sejak 7.0 i.stack.imgur.com/8pDGT.png
Martin Smith
Tampaknya menjadi halaman 6 (FYI untuk siapa pun yang datang ke utas nanti).
Peter Vandivier

Jawaban:

6

Ini tidak ada hubungannya dengan pemesanan nama objek di TempDB atau ada hubungannya dengan runtime. Ini hanyalah parser yang tidak dapat mengikuti jalur logika atau kode yang memastikan bahwa kode Anda tidak mungkin mencoba membuat tabel itu dua kali. Perhatikan bahwa Anda mendapatkan kesalahan (non-runtime!) Yang sama persis jika Anda cukup mengklik tombol Parse ( Ctrl+ F5). Pada dasarnya, jika Anda memiliki ini:

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

Parser melihat ini:

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

Mengapa tidak berfungsi seperti ini untuk tabel aktual , termasuk tabel pengguna aktual yang dibuat di TempDB (perhatikan bahwa tabel itu juga tidak khusus untuk basis data)? Satu-satunya jawaban yang dapat saya sarankan adalah bahwa parser memiliki seperangkat aturan yang berbeda untuk tabel #temp (ada banyak perbedaan lain juga). Jika Anda ingin alasan yang lebih spesifik, Anda harus membuka kasing dengan Microsoft dan melihat apakah mereka akan memberi Anda rincian lebih lanjut. Dugaan saya adalah Anda akan diberi tahu: "ini cara kerjanya."

Beberapa info lebih lanjut dalam jawaban ini:

Aaron Bertrand
sumber
Bahkan, " ini cara kerjanya " adalah respons yang mereka miliki. Oh well ...
Peter Vandivier