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 into
pernyataan yang akan dieksekusi karena mereka dibungkus di dalam if-else
blok. 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 #foo
ditempatkan 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 TempDB
objek 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.
sumber
Jawaban:
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:
Parser melihat ini:
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:
sumber