SELECT INTO riserva il nome oggetto # in TempDB prima del runtime?


8

Mettendo insieme una procedura rapida per aiutare con il debug, mi sono imbattuto in quello che sembra essere un errore nel compilatore.

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;

Tentare quanto sopra restituisce il seguente errore

Messaggio 2714, livello 16, stato 1, procedura spFoo, riga 19
Nel database è già presente un oggetto denominato "#bar".

In un senso leggibile dall'uomo, il proc sembra andare bene: select intosarà mai eseguita solo un'istruzione poiché sono racchiuse nei if-elseblocchi. Molto bene, tuttavia, il server SQL non può confermare che le istruzioni siano logicamente escluse l'una dall'altra. Forse forse più confuso è che l'errore rimane quando drop table #fooviene inserito all'interno del blocco if-else (che si presume direbbe al compilatore di deallocare il nome dell'oggetto) come di seguito.

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;

Lo stesso proc va bene. L'ho succhiato e ho scritto le dichiarazioni create table #foo( ... )e insert #foo ( ... ), avevo cercato di saltare con la select * into sintassi. A questo punto, sto solo cercando di capire perché il compilatore è saltato fuori con la sintassi del tipo pigro. L'unica cosa che mi viene in mente è che il comando DDL riserva il nome dell'oggetto IN TEMPDB .

Perché il testo in grassetto?

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

Questo non riesce con lo stesso codice di errore di cui sopra. Ma il seguente ...

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

... ci riesce. Lo stesso vale per il tentativo proc originale. Così...

La mia domanda è questa

Qual è la differenza (e perché è presente) nella prenotazione del nome oggetto per gli TempDBoggetti rispetto ai database degli utenti. Nessuno dei riferimenti sull'elaborazione della query logica né i riferimenti ai comandi DDL che ho esaminato sembrano spiegare questo.


1
Questo screenshot di "La guida del guru alle procedure memorizzate, XML e HTML di SQL Server" (su Google Libri) sembra pertinente e indica che questo è stato il modo in cui funziona dal 7.0 i.stack.imgur.com/8pDGT.png
Martin Smith

Sembra essere pagina 6 (FYI per chiunque venga alla discussione in seguito).
Peter Vandivier,

Risposte:


6

Questo non ha nulla a che fare con le prenotazioni dei nomi degli oggetti in TempDB o con il runtime. Questo è semplicemente il parser che non è in grado di seguire percorsi logici o di codice che assicura che il tuo codice non possa provare a creare quella tabella due volte. Si noti che si ottiene lo stesso identico errore (non di runtime!) Se si fa semplicemente clic sul pulsante Analizza ( Ctrl+ F5). Fondamentalmente, se hai questo:

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

Il parser vede questo:

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

Perché non funziona in questo modo per le tabelle effettive , comprese le tabelle utente effettive create in TempDB (si noti che non è nemmeno specifico del database)? L'unica risposta che posso suggerire è che il parser ha un diverso insieme di regole per le tabelle #temp (ci sono anche molte altre differenze). Se desideri motivi più specifici, dovrai aprire un caso con Microsoft e vedere se ti forniranno ulteriori dettagli. Suppongo che ti verrà detto: "questo è il modo in cui funziona".

Altre informazioni in queste risposte:


In effetti, " questo è il modo in cui funziona " è esattamente la risposta che hanno. Oh bene ...
Peter Vandivier,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.