Compruebe si existe una tabla temporal y elimínela si existe antes de crear una tabla temporal


663

Estoy usando el siguiente código para verificar si la tabla temporal existe y soltar la tabla si existe antes de crear nuevamente. Funciona bien siempre que no cambie las columnas. Si agrego una columna más tarde, aparecerá un error que dice "columna no válida". Por favor, hágame saber lo que estoy haciendo mal.

IF OBJECT_ID('tempdb..#Results') IS NOT NULL
    DROP TABLE #Results

CREATE TABLE #Results
(
    Company                CHAR(3),
    StepId                TINYINT,
    FieldId                TINYINT,
)

select company, stepid, fieldid from #Results

--Works fine to this point

IF OBJECT_ID('tempdb..#Results') IS NOT NULL
    DROP TABLE #Results

CREATE TABLE #Results
(
    Company                CHAR(3),
    StepId                TINYINT,
    FieldId                TINYINT,
    NewColumn            NVARCHAR(50)
)

select company, stepid, fieldid, NewColumn from #Results

--Does not work

¿Dónde estás agregando la columna? ¿Puedes publicar el código exacto que te está dando un error?
Macros

Estoy agregando la columna a la tabla #Resultados. Si copia el código anterior y lo ejecuta por primera vez, no obtendrá ningún error. Ahora, si agrega una columna a la tabla temporal y agrega la columna a la instrucción select, dirá columna no encontrada (o algo así).
Sridhar

22
Considere el uso de la distribución siguiente: BEGIN TRANSACTION; CREATE TABLE #Results; ...; DROP TABLE #Results; COMMIT. Si la transacción tiene éxito, la tabla se eliminará. Si falla, la tabla también desaparecerá (ya que se creó dentro de la transacción). En cualquier caso: no es necesario verificar si la tabla ya existe.
Heinzi

1
Parece que solo necesitas declaraciones GO.
Sam yi

Respuestas:


734

No puedo reproducir el error.

Quizás no entiendo el problema.

Lo siguiente funciona bien para mí en SQL Server 2005, con la columna "foo" adicional que aparece en el segundo resultado de selección:

IF OBJECT_ID('tempdb..#Results') IS NOT NULL DROP TABLE #Results
GO
CREATE TABLE #Results ( Company CHAR(3), StepId TINYINT, FieldId TINYINT )
GO
select company, stepid, fieldid from #Results
GO
ALTER TABLE #Results ADD foo VARCHAR(50) NULL
GO
select company, stepid, fieldid, foo from #Results
GO
IF OBJECT_ID('tempdb..#Results') IS NOT NULL DROP TABLE #Results
GO

1
SI OBJECT_ID ('tempdb .. # Results') NO ES NULL DROP TABLE # Results` CREATE TABLE #Results (Company CHAR (3), StepId INT) selecciona la compañía, stepid de #results ahora vuelve a la declaración de creación y agrega un column fieldid al final. cambie la instrucción select para incluir fieldid y ejecútelo.
Sridhar

28
'tempdb..#name'es exactamente lo que necesitaba Estaba usando 'dbo.#name', como un tonto. Me sale el tempdbpapel, pero ¿qué pasa con los puntos dobles?
Conrad

77
@ Conrad.Dean double dot es una abreviatura de .dbo.
deutschZuid

32
@deutschZuid es más exacto decir que el punto doble es el esquema predeterminado del usuario, que normalmente es dbo (que no es una gran idea, lo que hace que dbo sea el esquema predeterminado para los usuarios, pero así suele ser)
jcollum

8
Su código es tan diferente del OP que su declaración 'no se puede reproducir' no tiene sentido. Me alegra que hayas conseguido que funcione de otra manera.
Gerard ONeill

85

La declaración debe ser del orden

  1. Alterar la declaración para la mesa
  2. VAMOS
  3. Seleccionar declaración.

Sin 'GO' en el medio, todo se considerará como un solo script y cuando la instrucción select busca la columna, no se encontrará.

Con 'GO', considerará la parte del script hasta 'GO' como un solo lote y se ejecutará antes de entrar en la consulta después de 'GO'.


77
Esto debe marcarse como la respuesta correcta. No es que SELECT vaya a ejecutarse antes que la tabla de creación, es que se está analizando y arroja un error antes de ejecutarse, porque hay una tabla existente llamada #Results que aún no tiene la columna FieldId en el hora en que se analiza la instrucción select. Agregar un GO allí separa la consulta en lotes, que se analizan y ejecutan por separado.
Davos

2
No puedo creer la disparidad en los votos entre esta y la respuesta principal, que cambió tanto el código, sin explicar por qué, que no tenía sentido como respuesta.
underscore_d

63

En lugar de droppingvolver a crear la tabla temporal, puede truncatereutilizarla

IF OBJECT_ID('tempdb..#Results') IS NOT NULL
    Truncate TABLE #Results
else
    CREATE TABLE #Results
    (
        Company             CHAR(3),
        StepId              TINYINT,
        FieldId             TINYINT,
    )

Si está utilizando Sql Server 2016o Azure Sql Databaseluego utiliza la sintaxis siguiente para descartar la tabla temporal y volver a crearla. Más información aquí MSDN

Sintaxis

DROP TABLE [IF EXISTS] [nombre_base_datos. [nombre_esquema]. El | nombre_esquema. ] nombre_tabla [, ... n]

Consulta:

DROP TABLE IF EXISTS tempdb.dbo.#Results
CREATE TABLE #Results
  (
   Company             CHAR(3),
   StepId              TINYINT,
   FieldId             TINYINT,
  )

Parece que el truncate/reusemétodo sería más eficiente que el DROP TABLE IF EXISTSencendido Sql Server 2016y Azure Sql Databasetambién. ¿No es este el caso?
JDawg

@prdp ¿Por qué sugiere DROP TABLE IF Existspara SQL 2016 o Azure? La sintaxis está disponible a partir de SQL 2008. ¿Ver el enlace de MSDN en su respuesta? Factor de rendimiento?
HappyTown

44
No importa. Ahora me di cuenta, DROP TABLEes compatible con SQL Server 2008, pero la IF EXISTScláusula se introdujo en 2016.
HappyTown

1
Yo uso INTO: seleccione * INTO #HistoricoUserTable de dbo.HistoricoUser
Kiquenet

54

Creo que el problema es que necesita agregar una declaración GO en el medio para separar la ejecución en lotes. Como el segundo script de caída, es decir, IF OBJECT_ID('tempdb..#Results') IS NOT NULL DROP TABLE #Resultsno dejó caer la tabla temporal como parte de un solo lote. ¿Puedes probar el siguiente script?

IF OBJECT_ID('tempdb..#Results') IS NOT NULL
    DROP TABLE #Results

CREATE TABLE #Results
(
    Company                CHAR(3),
    StepId                TINYINT,
    FieldId                TINYINT,
)

GO

select company, stepid, fieldid from #Results

IF OBJECT_ID('tempdb..#Results') IS NOT NULL
DROP TABLE #Results

CREATE TABLE #Results
(
    Company                CHAR(3),
    StepId                TINYINT,
    FieldId                TINYINT,
    NewColumn            NVARCHAR(50)
)

GO

select company, stepid, fieldid, NewColumn from #Results

1
De nota; tempdb..en el código de arriba es muy importante. Debe preceder al nombre de la tabla temporal. Simplemente verificar OBJECT_ID('#Results')no es suficiente. Las tablas temporales se almacenan en la base de datos TempDB. Según Microsoft: la base de datos del sistema TempDB es un recurso global que está disponible para todos los usuarios conectados a la instancia de SQL Server o conectados a la base de datos SQL
iCode

Gracias, @iCode. Esa es la clave para descartar las tablas temporales: debe hacerse tempdbo no desaparecerá.
Alex

37

Esto podría lograrse con una sola línea de código:

IF OBJECT_ID('tempdb..#tempTableName') IS NOT NULL DROP TABLE #tempTableName;   

1
Debo ver esto todos los días
Ab Bennett

28

Esto funcionó para mí: social.msdn.microsoft.com/Forums/en/transactsql/thread/02c6da90-954d-487d-a823-e24b891ec1b0?prof=required

if exists (
    select  * from tempdb.dbo.sysobjects o
    where o.xtype in ('U') 

   and o.id = object_id(N'tempdb..#tempTable')
)
DROP TABLE #tempTable;

1
Esta es una sintaxis diferente para la caída de la tabla condicional. Es interesante pero no resuelve la pregunta del OP, y la mayor parte es redundante. Si solo verifica que OBJECT_ID (N'tempdb .. # Results ') no es nulo, entonces eso es suficiente para demostrar que el objeto ya existe.
Davos

21

Solo un pequeño comentario de mi parte ya OBJECT_IDque no funciona para mí. Siempre devuelve eso

`#tempTable no existe

..even pesar de que hace existir. Acabo de encontrar que está almacenado con un nombre diferente (pospuesto con _guiones bajos) así:

#tempTable________

Esto funciona bien para mi:

IF EXISTS(SELECT [name] FROM tempdb.sys.tables WHERE [name] like '#tempTable%') BEGIN
   DROP TABLE #tempTable;
END;

66
Precaución: ese código detectará una tabla si fue creada por algún hilo. Las tablas temp # individuales se crean por separado por subproceso / llamador a un proceso almacenado, por lo que se subraya el nombre para que exista una copia diferente por subproceso / proceso. El Object_ID debería funcionar bien para el hilo actual, siempre que esté en SQL 2005 o posterior.
Bytemaster

12

Ahora puede usar la sintaxis a continuación si está utilizando una de las nuevas versiones de SQL Server (2016+).

DROP TABLE IF EXISTS schema.yourtable(even temporary tables #...)

1
Estoy usando SSMS 17.3 y esto daIncorrect syntax near the keyword 'IF'.
StingyJack

77
@StingyJack Porque la sintaxis SQL no está relacionada con la versión de SSMS, sino con la versión de SQL Server. La IF [NOT] EXISTScláusula está disponible en SQL Server 2016. No importa qué versión de SSMS esté utilizando.
Pred

10

pmac72 está usando GO para dividir la consulta en lotes y está usando ALTER.

Parece que está ejecutando el mismo lote pero ejecutándolo dos veces después de cambiarlo: DROP ... CREATE ... edit ... DROP ... CREATE ..

Quizás publique su código exacto para que podamos ver lo que está sucediendo.


7

Por lo general, aparece este error cuando ya he creado la tabla temporal; el código que verifica la instrucción SQL en busca de errores ve la tabla temporal "antigua" en su lugar y devuelve un recuento incorrecto del número de columnas en las declaraciones posteriores, como si la tabla temporal nunca se descartara.

Después de cambiar el número de columnas en una tabla temporal después de crear una versión con menos columnas, suelte la tabla y LUEGO ejecute su consulta.


6

Hace poco vi un DBA hacer algo similar a esto:

begin try
    drop table #temp
end try

begin catch 
    print 'table does not exist'
end catch 

create table #temp(a int, b int)

2
Esta declaración de prueba detectaría otros errores que podrían ocurrir al intentar abandonar la tabla. Este código supone que la única razón por la que el intento podría fallar es porque la tabla no existe. Probablemente funcionaría la mayor parte del tiempo, pero no lo garantizaría. Si la declaración de prueba falla por alguna otra razón, obtendrá un error al crear la tabla, porque esto ha enmascarado el problema real al abandonar la tabla.
Davos

Esto funciona pero es malo. No animo de la manera difícil cuando hay una solución inteligente y perfecta. Y también, aunque OP especificó la versión 2005, intente el bloque catch no es compatible con versiones anteriores
dejjub-AIS

El otro problema con esto es la ideología de usar try / catch vs logic. Puede ver más del debate aquí: stackoverflow.com/questions/17335217/try-catch-or-if-statement/…
logixologist

3

Mi código usa una Sourcetabla que cambia y una Destinationtabla que debe coincidir con esos cambios.

-- 
-- Sample SQL to update only rows in a "Destination" Table
--  based on only rows that have changed in a "Source" table
--


--
-- Drop and Create a Temp Table to use as the "Source" Table
--
IF OBJECT_ID('tempdb..#tSource') IS NOT NULL drop table #tSource
create table #tSource (Col1 int, Col2 int, Col3 int, Col4 int)

--
-- Insert some values into the source
--
Insert #tSource (Col1, Col2, Col3, Col4) Values(1,1,1,1)
Insert #tSource (Col1, Col2, Col3, Col4) Values(2,1,1,2)
Insert #tSource (Col1, Col2, Col3, Col4) Values(3,1,1,3)
Insert #tSource (Col1, Col2, Col3, Col4) Values(4,1,1,4)
Insert #tSource (Col1, Col2, Col3, Col4) Values(5,1,1,5)
Insert #tSource (Col1, Col2, Col3, Col4) Values(6,1,1,6)

--
-- Drop and Create a Temp Table to use as the "Destination" Table
--
IF OBJECT_ID('tempdb..#tDest') IS NOT NULL drop Table #tDest
create table #tDest (Col1 int, Col2 int, Col3 int, Col4 int)

--
-- Add all Rows from the Source to the Destination
--
Insert #tDest
Select Col1, Col2, Col3, Col4 from #tSource


--
-- Look at both tables to see that they are the same
--
select *
from #tSource
Select *
from #tDest

--
-- Make some changes to the Source
--
update #tSource
    Set Col3=19
    Where Col1=1
update #tSource
    Set Col3=29
    Where Col1=2
update #tSource
    Set Col2=38
    Where Col1=3
update #tSource
    Set Col2=48
    Where Col1=4

--
-- Look at the Differences
-- Note: Only 4 rows are different. 2 Rows have remained the same.
--
Select Col1, Col2, Col3, Col4
from #tSource
except
Select Col1, Col2, Col3, Col4
from #tDest

--
-- Update only the rows that have changed
-- Note: I am using Col1 like an ID column
--
Update #tDest
    Set Col2=S.Col2,
        Col3=S.Col3,
        Col4=S.Col4
From    (   Select Col1, Col2, Col3, Col4
            from #tSource
            except
            Select Col1, Col2, Col3, Col4
            from #tDest
        ) S
Where #tDest.Col1=S.Col1 

--
-- Look at the tables again to see that
--  the destination table has changed to match
--  the source table.

select *
from #tSource
Select *
from #tDest

--
-- Clean Up
--
drop table #tSource
drop table #tDest

1

Sí, "columna no válida", este error surgió de la línea "seleccionar empresa, stepid, fieldid, NewColumn de #Results".

Hay dos fases de ejecución de t-sql,

primero, analizando, en esta fase, el servidor sql verifica la corrección de la cadena sql enviada, incluida la columna de la tabla, y optimiza su consulta para una recuperación más rápida.

segundo, corriendo, recuperando los datos.

Si la tabla #Results existe, el proceso de análisis verificará que las columnas que especificó sean válidas o no, de lo contrario (la tabla no existe) el análisis se pasará por las columnas de comprobación como usted especificó.


0

Cuando cambia una columna en una tabla temporal, debe soltar la tabla antes de volver a ejecutar la consulta. (Sí, es molesto. Justo lo que tienes que hacer).

Siempre he asumido que esto se debe a que el analizador realiza la comprobación de "columna no válida" antes de ejecutar la consulta, por lo que se basa en las columnas de la tabla antes de que se descarte ... y eso es lo que pnbs también dijo.

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.