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 into
se ejecutará una sola declaración, ya que están dentro de los if-else
bloques. 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 #foo
se 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 TempDB
objetos 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.
fuente
Respuestas:
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:
El analizador ve esto:
¿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:
fuente