2008-09-23 7 views
5

Estaba escribiendo un fragmento SQL (aparentemente) sencillo que deja caer una columna después de asegurarse de que la columna exista.
El problema: si la columna NO existe, el código dentro de ¡la cláusula IF se queja de que no puede encontrar la columna! Bueno, doh, ¡es por eso que está dentro de la cláusula IF!
Entonces mi pregunta es, ¿por qué un fragmento de código que no debe ejecutarse produce errores?¿Por qué un bloque T-SQL genera un error incluso si ni siquiera se debería ejecutar?

Aquí está el fragmento:

IF exists (select * from syscolumns 
    WHERE id=object_id('Table_MD') and name='timeout') 
BEGIN 
    ALTER TABLE [dbo].[Table_MD] 
     DROP COLUMN timeout 
END 
GO 

... y aquí está el error:

Error executing SQL script [...]. Invalid column name 'timeout'

estoy usando Microsoft SQL Server 2005 Express Edition.

Respuesta

10
IF exists (select * from syscolumns 
    WHERE id=object_id('Table_MD') and name='timeout') 
BEGIN 
    DECLARE @SQL nvarchar(1000) 
    SET @SQL = N'ALTER TABLE [dbo].[Table_MD] DROP COLUMN timeout' 
    EXEC sp_executesql @SQL 
END 
GO 

Motivo: Cuando el servidor SQL compila el código, que comprobar que los objetos usados ​​(si es que existe) . Este procedimiento de verificación ignora las construcciones "IF", "WHILE", etc ... y simplemente verifica todos los objetos usados ​​en el código.

+0

Correcto. También obtendrá este error si hay tablas temporales que utiliza sproc. – ConcernedOfTunbridgeWells

+0

Para aclarar, si existe una tabla temporal, entonces las columnas se verificarán cuando compile el sproc. Donde el sproc realmente crea la tabla (por ejemplo, con una selección en) puede que tenga que soltar la tabla antes de volver a compilar el sproc. – ConcernedOfTunbridgeWells

+0

Esta es una muy buena respuesta :) –

0

Es posible que nunca se ejecute, pero Sql Server lo analiza para que sea válido. La única manera de "moverse" esta es la construcción de un bloque de SQL dinámico y luego ejecutar selectivamente

0

Así es como llegué a trabajar:

Dentro de la cláusula IF, he cambiado el comando ALTER ... DROP ... con exec ('ALTER ... DROP ...')

Parece que el servidor SQL hace una comprobación de validez en el código cuando analizarlo, y ve que una columna no existente se referencia en alguna parte (incluso si ese fragmento de código nunca se ejecutará).
Al utilizar el comando exec(ute) se envuelve el código problemático en una cadena, el analizador no se queja y el código solo se ejecuta cuando es necesario. Aquí está el fragmento modificado:

IF exists (select * from syscolumns 
    WHERE id=object_id('Table_MD') and name='timeout') 
BEGIN 
    exec ('ALTER TABLE [dbo].[Table_MD] DROP COLUMN timeout') 
END 
GO 
0

Por cierto, hay un problema similar en Oracle, y una solución similar utilizando la cláusula de "ejecución inmediata".

Cuestiones relacionadas