如果所有表都不存在,请添加一列?

Posted

技术标签:

【中文标题】如果所有表都不存在,请添加一列?【英文标题】:Add a column if it doesn't exist to all tables? 【发布时间】:2011-07-05 23:42:45 【问题描述】:

我使用的是 SQL Server 2005/2008。如果表尚不存在,我需要向表中添加一列。这将适用于给定数据库中的所有表。我希望我很接近,但我遇到了这个解决方案的问题。

如何做到这一点?

这是我所拥有的:

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
'

但我得到错误:

错误 102:“@tblname”附近的语法不正确。 “CreatedOn”附近的语法不正确。 '@tblname' 附近的语法不正确。 “CreatedOn”附近的语法不正确。 ... 等等,对于每个表。

【问题讨论】:

***.com/questions/1779743/… 的可能重复项 @JAiro:这绝对是一个相关的链接,但是“如果不存在”规则很重要,并且让它变得更复杂一些。 好的,你可以用这个来完成信息:***.com/questions/133031/… 您问题的根本原因是依赖于 INFORMATION_SCHEMA 视图并且必须将名称拆分为模式和对象。只需使用object_id(''?'') 就可以了。更快的检查是if COLUMNPROPERTY(object_id(''?''), ''CreatedOn'', ''ColumnId'') is null 【参考方案1】:

您不能在 DDL 中使用变量,例如 @tableName。此外,将名称分成部分并忽略模式只会导致错误。您应该只在 SQL 批处理参数中使用 ''?'' 替换并依赖 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';

【讨论】:

请记住,sp_msforeachtable 是不受支持的存储过程,因此不应将其用于生产代码。尽管它添加了几行代码,但如果您使用定义为从 sys.schemas 和 sys.tables 中选择的 游标,则您使用的是 T-SQL 的文档化部分,您可以选择只改变一个WHERE表达式就可以影响全部或部分表,性能是一样的。此外,如果您使用 quotename 函数,您可以处理更少的名称限定符。最后,您可以更灵活地使用您希望的架构/表名称(即用于日志)。 @PhilHelmer 这连同一个例子会是一个很好的答案。【参考方案2】:

您需要混合一些动态 SQL。这应该有效:

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
'

【讨论】:

@Remus:是的,如果 OP 正在使用模式,那么这将成为一个问题。为您的回答 +1。【参考方案3】:

DECLARE @Column VARCHAR(100) = 'Inserted_date'
DECLARE @sql VARCHAR(max) = NULL

SELECT @sql += ' ALTER TABLE ' + QUOTENAME(TABLE_SCHEMA) + '.' + QUOTENAME(TABLE_NAME) + 'ADD' + @Column + 'datetime NOT NULL DEFAULT getdate()' + '; '
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_TYPE = 'BASE TABLE'
    AND TABLE_NAME IN (
        SELECT DISTINCT NAME
        FROM SYS.TABLES
        WHERE type = 'U'
            AND Object_id IN (
                SELECT DISTINCT Object_id
                FROM SYS.COLUMNS
                WHERE NAME != @Column
                )
        )
EXEC Sp_executesql @sql

【讨论】:

考虑为您的答案添加解释。也许也删除代码的屏幕截图...... 嗨,Jean,实际上我只是将列名存储在一个变量中,并找出该特定列不存在的表名,然后将 alter 命令保存在另一个变量 @sql 中我们运行执行添加。【参考方案4】:

可能是这样的:

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
'

?

甚至像这样:

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
'

【讨论】:

-1 在发布之前显然没有对此进行测试。 [?] 在已经用括号括起来的名称周围添加括号,导致 [[schemaname].[tablename]] 这是不正确的。 @Remus Rusanu:我对此进行了测试:sp_MSforeachtable 'EXEC sp_help ?; EXEC sp_columns ?'。这给出了语法错误。然后我把它改成sp_MSforeachtable 'EXEC sp_help [?]; EXEC sp_columns [?]',它工作了(SQL Server 2008 R2)。 ...但是您没有测试 OP ALTER TABLE [?]sp_helpsp_columns 都是存储过程,? 替换不起作用,因为 sp_help [foo].[bar] 是无效语法。但是sp_help [[foo]].[bar]]] 是正确的语法,并且由于参数的处理方式,它实际上最终可以工作。 ALTER TABLE [[foo]].[bar]]] 虽然不起作用。长话短说:您发布的代码没有通过基本的语法检查,任何人都可以验证。 @Remus Rusanu:我不是在争论。我发布我的测试示例有两个原因:提供我错觉的原因,并可能有人解释我为什么会被错觉(除了我无知的明显原因)。所以,最后,谢谢。 :) 哦,对不起,我误解了你的 cmets。 sp_help [?] 的工作方式至少对我来说也很神秘。

以上是关于如果所有表都不存在,请添加一列?的主要内容,如果未能解决你的问题,请参考以下文章

mysql中先判断数据是不是存在,如存在则增加数量,不存在则增加一条记录

mysql提示table不存在:把数据库里的表都删了,用sql重新建表,怎么还提示表不存在呢?是在服务器上

SQL - 如果不存在

mysql 的表已经存在,但是我现在想添加一列 自动增长列

MySQL 加入日期列存在 1 个月的滞后和性能问题

外键的引用说表不存在