¿SELECT INTO reserva el nombre del #Object en TempDB antes del tiempo de ejecución?

8

Al reunir un proceso rápido para ayudar con la depuración, me encontré con lo que parece ser un error en el compilador.

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;

Intentar lo anterior devuelve el siguiente error

Mensaje 2714, Nivel 16, Estado 1, Procedimiento spFoo, Línea 19
Ya existe un objeto llamado '#bar' en la base de datos.

En un sentido legible para los humanos, el proceso parece estar bien: solo select intose ejecutará una sola declaración, ya que están dentro de los if-elsebloques. Sin embargo, muy bien, el servidor SQL no puede confirmar que las declaraciones estén lógicamente excluidas entre sí. Quizás más confuso es que el error permanece cuando drop table #foose coloca dentro del bloque if-else (que se supone que le indicaría al compilador que desasigne el nombre del objeto) como se muestra a continuación.

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;

El proceso en sí está bien. Lo absorbí y escribí las declaraciones create table #foo( ... )y insert #foo ( ... ), había estado tratando de saltarme la select * into sintaxis. En este punto, solo estoy tratando de entender por qué el compilador me criticó con la sintaxis del tipo vago. Lo único que puedo pensar es que el comando DDL reserva el nombre del objeto EN TEMPDB .

¿Por qué el texto en negrita?

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

Esto falla con el mismo código de error que el anterior. Pero lo siguiente ...

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

... tiene éxito. Lo mismo sigue arriba al intento de proceso original. Entonces...

Mi pregunta es esta

¿Cuál es la diferencia (y por qué está presente) en la reserva de nombre de objeto para TempDBobjetos en lugar de bases de datos de usuario? Ninguna de las referencias de Procesamiento de consultas lógicas ni las referencias de comandos DDL que he revisado parecen explicar esto.

Peter Vandivier
fuente
1
Esta captura de pantalla de "La guía del gurú sobre procedimientos almacenados de SQL Server, XML y HTML" (en Google Books) parece relevante e indica que ha sido así desde 7.0 i.stack.imgur.com/8pDGT.png
Martin Smith
Parece ser la página 6 (FYI para cualquier persona que llegue al hilo más tarde).
Peter Vandivier

Respuestas:

6

Esto no tiene nada que ver con las reservas de nombre de objeto en TempDB ni con el tiempo de ejecución. Este es simplemente el analizador que no puede seguir la lógica o las rutas de código que aseguran que su código no podría intentar crear esa tabla dos veces. Tenga en cuenta que obtiene exactamente el mismo error (¡no en tiempo de ejecución!) Si solo hace clic en el botón Analizar ( Ctrl+ F5). Básicamente, si tienes esto:

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

El analizador ve esto:

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

¿Por qué no funciona de esta manera para las tablas reales , incluidas las tablas de usuarios reales creadas en TempDB (tenga en cuenta que tampoco es específica de la base de datos)? La única respuesta que puedo sugerir es que el analizador tiene un conjunto diferente de reglas para las tablas #temp (también hay muchas otras diferencias). Si desea razones más específicas, deberá abrir un caso con Microsoft y ver si le darán más detalles. Supongo que se le dirá: "así es como funciona".

Más información en estas respuestas:

Aaron Bertrand
fuente
De hecho, " esta es la forma en que funciona " es exactamente la respuesta que tienen. Oh bueno ...
Peter Vandivier