2011-01-28 15 views
6

Antecedentes: hay un procedimiento almacenado que hace "cosas" con una tabla temporal de un nombre de pila. El procedimiento es genérico porque inspecciona el esquema de la tabla temporal y luego hace diferentes "cosas" dependiendo del esquema. Entiendo que esto es un poco raro, pero me resisto a cambiarlo porque funciona bien en la mayoría de las situaciones, excepto ....¿Por qué SQL Server piensa que ya existe una tabla temporal cuando no lo hace?

Si tengo un procedimiento almacenado que crea dos esquemas diferentes para una tabla temporal con el mismo nombre. Lógicamente, solo crea una tabla temporal según la rama del IF. El problema es que cuando el sproc está marcada por SQL Server parece que está evaluando ambos lados de la SI

Así que este SQL falla (lo cual tiene sentido si se trata de comprobar la sintaxis SQL.):

IF (1=1) 
BEGIN 
    CREATE TABLE #test 
    (
     a BIGINT NOT NULL, 
     b BIGINT NOT NULL 
    ) 
END 
ELSE 
BEGIN 
    CREATE TABLE #test 
    (
     a BIGINT NOT NULL, 
     b BIGINT NOT NULL, 
     c BIGINT NOT NULL 
    ) 
END 

--exec SomeProcedureWhichDoesStuffWith#Test 

DROP TABLE #test 

con el error siguiente:

Msg 2714, Level 16, State 1, Line 14
There is already an object named '#test' in the database.

No combinación de tabla de la gota dentro de las ifs (antes o después de la tabla crear DDL) parece satisfacer el corrector sql.

¿Alguna idea de cómo puedo hacer esto? ¿Puedo, por ejemplo, decirle a SQL que no realice la verificación de sintaxis y simplemente aceptar el sproc tal como está?

Respuesta

6

Es una limitación. SQL dinámico tampoco funcionará, ya que #tmp se creará en una sesión nueva y se perderá inmediatamente. Para el fragmento EXACTA como se muestra, esto hace lo mismo

CREATE TABLE #test 
(
    a BIGINT NOT NULL, 
    b BIGINT NOT NULL 
) 

IF not (1=1) 
    ALTER TABLE #test ADD c BIGINT NOT NULL 

No puede haber dos crean .. #nombre dentro del mismo lote, pero esto también trabajará en forma general

IF (1=1) 
BEGIN 
    CREATE TABLE #test 
    (
     a BIGINT NOT NULL, 
     b BIGINT NOT NULL 
    ); 
END 
GO 

IF NOT (1=1) 
BEGIN 
    CREATE TABLE #test 
    (
     a BIGINT NOT NULL, 
     b BIGINT NOT NULL, 
     c BIGINT NOT NULL 
    ) 
END 
0

ya que yo no tener sql 2008, no puedo probarlo. sin embargo, que yo sepa, este es un problema de analizador explícitamente con tablas temporales. lo mismo podría funcionar bien con mesas normales

para solucionar esto, simplemente dividir su código con declaraciones GO lógicas

idealmente: comprobar la existencia de tablas temporales antes de crear sus tablas temporales, soltarlos si es que existen, disparar un ir, hacer la creación de tablas temporales de nuevo, disparar un ir, entonces cualquier procesamiento posterior, disparar un ir, finalmente dejarlas caer de nuevo y disparar el último Ir


también puede ser que desee probar y usar el tabla variable en lugar de tablas temporales si arriba no la resuelve

+0

Sí gracias por la información. Lamentablemente, está creando las tablas en un sproc, por lo que debe estar en el mismo lote (por lo tanto, no se debe continuar GO). –

0

Siempre se puede "engañar":

DECLARE @SQL VARCHAR(200) 

IF (1=1) 
BEGIN 
    SET @SQL = 'CREATE TABLE #Temp  ' + 
       '(      ' + 
       ' a BIGINT NOT NULL, ' + 
       ' b BIGINT NOT NULL ' + 
       ')      ' 
END 
ELSE 
BEGIN 
    SET @SQL = 'CREATE TABLE #Temp  ' + 
       '(      ' + 
       ' a BIGINT NOT NULL, ' + 
       ' b BIGINT NOT NULL, ' + 
       ' c BIGINT NOT NULL ' + 
       ')      ' 
END 

EXEC SP_EXECUTESQL @SQL 
+0

Eso no funcionará, ya que saldría inmediatamente del alcance y no se podría usar en el script externo. Tendría que ser una tabla temporal global o todos los usos de la tabla temporal deberían estar en el SQL dinámico. –

2

En lugar de #test, utilice un nombre completo. Por ejemplo,

[tempdb].[dbo].[temptable] 

Aprendí este pequeño truco aquí Insert result of executing dynamic query into a table.

Intellisense se quejará pero aún podrá crear o modificar el procedimiento almacenado.

cuando termine con él, asegúrese de dejarla caer:

DROP TABLE [tempdb].[dbo].[temptable] 
Cuestiones relacionadas