SELECT INTO réserve-t-il le nom de #Object dans TempDB avant l'exécution?

8

Mettre en place un proc quickie pour aider au débogage, j'ai rencontré ce qui semble être une erreur dans le compilateur.

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;

La tentative ci-dessus renvoie l'erreur suivante

Msg 2714, niveau 16, état 1, procédure spFoo, ligne 19
Il existe déjà un objet nommé '#bar' dans la base de données.

Dans un sens lisible par l'homme, le proc semble être bien: une seule select intoinstruction sera jamais exécutée car elles sont enveloppées à l'intérieur des if-elseblocs. Très bien cependant, SQL Server ne peut pas confirmer que les instructions sont logiquement exclues les unes des autres. Le plus déroutant est peut-être que l'erreur persiste lorsque le drop table #fooest placé à l'intérieur du bloc if-else (dont on suppose qu'il dirait au compilateur de désallouer le nom de l'objet) comme ci-dessous.

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;

Le proc lui-même est très bien. Je l'ai aspiré et j'ai écrit les déclarations create table #foo( ... )et insert #foo ( ... ), j'avais essayé de sauter avec la select * into syntaxe. À ce stade, j'essaie simplement de comprendre pourquoi le compilateur m'a chié avec la syntaxe paresseuse. La seule chose à laquelle je peux penser est que la commande DDL réserve le nom de l'objet IN TEMPDB .

Pourquoi le texte en gras?

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

Cela échoue avec le même code d'erreur que ci-dessus. Mais ce qui suit ...

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

... réussit. La même chose ci-dessus s'applique à la tentative de proc d'origine. Donc...

Ma question est la suivante

Quelle est la différence (et pourquoi est-elle présente) dans la réservation de nom d' TempDBobjet par opposition aux bases de données utilisateur. Aucune des références Logical Query Processing ni des références de commande DDL que j'ai examinées ne semble expliquer cela.

Peter Vandivier
la source
1
Cette capture d'écran de "The Guru's Guide to SQL Server Stored Procedures, XML, and HTML" (sur Google Books) semble pertinente et indique que c'est ainsi que cela fonctionne depuis la version 7.0 i.stack.imgur.com/8pDGT.png
Martin Smith
Semble être la page 6 (FYI pour toute personne venant au fil plus tard).
Peter Vandivier

Réponses:

6

Cela n'a rien à voir avec les réservations de nom d'objet dans TempDB ou à voir avec l'exécution. Il s'agit simplement de l'analyseur incapable de suivre la logique ou les chemins de code qui garantissent que votre code ne pourrait pas essayer de créer deux fois cette table. Notez que vous obtenez exactement la même erreur (hors exécution!) Si vous cliquez simplement sur le bouton Analyser ( Ctrl+ F5). Fondamentalement, si vous avez ceci:

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

L'analyseur voit ceci:

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

Pourquoi cela ne fonctionne-t-il pas de cette façon pour les tables réelles , y compris les tables utilisateur réelles créées dans TempDB (notez que ce n'est pas spécifique à la base de données non plus)? La seule réponse que je peux suggérer est que l'analyseur a un ensemble de règles différent pour les tables #temp (il y a aussi beaucoup d'autres différences). Si vous voulez des raisons plus spécifiques, vous devrez ouvrir un dossier avec Microsoft et voir si elles vous donneront plus de détails. Je suppose que l'on vous dira: "c'est ainsi que cela fonctionne".

Quelques informations supplémentaires dans ces réponses:

Aaron Bertrand
la source
En fait, " c'est ainsi que cela fonctionne " est exactement la réponse qu'ils ont.
Eh