2011-02-28 18 views
21

Estoy usando SQL Server 2005/2008. Necesito agregar una columna a una tabla si aún no existe. Esto aplicará a todas las tablas en una base de datos dada. Esperaba estar cerca, pero estoy teniendo problemas con esta solución.¿Agregar una columna si no existe para todas las tablas?

¿Cómo se puede hacer esto?

Esto es lo que tengo:

EXEC sp_MSforeachtable ' 
    declare @tblname varchar(255); 
    SET @tblname = PARSENAME("?",1); 

    if not exists (select column_name from INFORMATION_SCHEMA.columns 
        where table_name = @tblname and column_name = ''CreatedOn'') 
    begin 
     ALTER TABLE @tblname ADD CreatedOn datetime NOT NULL DEFAULT getdate(); 
    end 
' 

pero me da errores:

Error 102: sintaxis incorrecta cerca de '@tblname'. Sintaxis incorrecta cerca de 'CreatedOn'. Sintaxis incorrecta cerca de '@tblname'. Sintaxis incorrecta cerca de 'CreatedOn'. ... y así sucesivamente, para cada tabla.

+0

posible duplicado de http://stackoverflow.com/questions/1779743/adding-a-column- to-all-user-tables-in-t-sql – JAiro

+0

@JAiro: Definitivamente es un enlace relevante, pero la regla "si no existe" es importante y lo hace un poco más complejo. –

+0

ok para que pueda completar la información con esto: http://stackoverflow.com/questions/133031/how-to-check-if-column-exists-in-sql-server-table – JAiro

Respuesta

23

No puede utilizar variables, como @tablename, en DDL. Además, entablillar el nombre en parte e ignorar el esquema solo puede provocar errores. Usted sólo debe utilizar la sustitución '' en el parámetro SQL por lotes y se basan en la sustitución MSforeachtable '?':

EXEC sp_MSforeachtable ' 
if not exists (select * from sys.columns 
       where object_id = object_id(''?'') 
       and name = ''CreatedOn'') 
begin 
    ALTER TABLE ? ADD CreatedOn datetime NOT NULL DEFAULT getdate(); 
end'; 
+0

Tenga en cuenta que sp_msforeachtable es un procedimiento almacenado no compatible, por lo que no debe utilizarse para el código de producción. Aunque agrega algunas líneas de código, si usa un ** cursor ** definido como una selección de sys.schemas y sys.tables, está utilizando una parte documentada de T-SQL, tiene la opción de afectar a todos o algunas de las tablas simplemente cambiando una expresión WHERE, y el rendimiento es el mismo. Además, tiene menos calificadores de nombres para tratar si usa la función ** quotename **. Por último, tiene más flexibilidad para usar los nombres de esquema/tabla como desee (es decir, para un registro). –

+0

@PhilHelmer Esto junto con un ejemplo hubiera sido una gran respuesta. – xr280xr

4

Tendrá que mezclar un poco de SQL dinámico. Esto debería funcionar:

EXEC sp_MSforeachtable ' 
    declare @tblname varchar(255); 
    SET @tblname = PARSENAME("?",1); 
    declare @sql nvarchar(1000); 

    if not exists (select column_name from INFORMATION_SCHEMA.columns 
        where table_name = @tblname and column_name = ''CreatedOn'') 
    begin 
     set @sql = N''ALTER TABLE '' + @tblname + N'' ADD CreatedOn datetime NOT NULL DEFAULT getdate();'' 
     exec sp_executesql @sql 
    end 
' 
+0

¿Qué hay de dos tablas con el mismo nombre en diferentes esquemas? 'foo.t' y' bar.t' ... –

+0

@Remus: Sí, si OP usa esquemas, entonces esto se convierte en un problema. +1 a tu respuesta. –

0

Tal como esto:

EXEC sp_MSforeachtable ' 
    declare @tblname varchar(255); 
    SET @tblname = PARSENAME("?",1); 

    if not exists (select column_name from INFORMATION_SCHEMA.columns 
        where table_name = @tblname and column_name = ''CreatedOn'') 
    begin 
     ALTER TABLE [?] ADD CreatedOn datetime NOT NULL DEFAULT getdate(); 
    end 
' 

?

ni aun como este:

EXEC sp_MSforeachtable ' 
    if not exists (select column_name from INFORMATION_SCHEMA.columns 
        where table_name = ''?'' and column_name = ''CreatedOn'') 
    begin 
     ALTER TABLE [?] ADD CreatedOn datetime NOT NULL DEFAULT getdate(); 
    end 
' 
+2

-1 obviamente no han probado esto antes de publicarlo. '[?]' agrega un corchete alrededor de un nombre ya entre corchetes, lo que da como resultado '[[schemaname]. [tablename]]' que es incorrecto. –

+0

@Remus Rusanu: He probado esto: 'sp_MSforeachtable 'EXEC sp_help?; EXEC sp_columns? ''. Eso dio un error de sintaxis. Luego lo cambié a 'sp_MSforeachtable 'EXEC sp_help [?]; EXEC sp_columns [?] '', Y funcionó (SQL Server 2008 R2). –

+0

... pero no ha probado OP 'ALTER TABLE [?]'. Ambos 'sp_help' y' sp_columns' son procedimientos almacenados, y el reemplazo '?' No va a funcionar porque 'sp_help [foo]. [Bar]' es una sintaxis inválida. Pero 'sp_help [[foo]]. [Bar]]]' es la sintaxis correcta y, debido a la forma en que se manejan los parámetros, en realidad termina funcionando. 'ALTER TABLE [[foo]]. [Bar]]]' aunque no funciona. Demasiado corto: el código que publicaste no pasa las verificaciones de sintaxis básicas, y esto puede ser verificado por cualquiera. –

Cuestiones relacionadas