如果所有表都不存在,请添加一列?
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_help
和 sp_columns
都是存储过程,?
替换不起作用,因为 sp_help [foo].[bar]
是无效语法。但是sp_help [[foo]].[bar]]]
是正确的语法,并且由于参数的处理方式,它实际上最终可以工作。 ALTER TABLE [[foo]].[bar]]]
虽然不起作用。长话短说:您发布的代码没有通过基本的语法检查,任何人都可以验证。
@Remus Rusanu:我不是在争论。我发布我的测试示例有两个原因:提供我错觉的原因,并可能有人解释我为什么会被错觉(除了我无知的明显原因)。所以,最后,谢谢。 :)
哦,对不起,我误解了你的 cmets。 sp_help [?]
的工作方式至少对我来说也很神秘。以上是关于如果所有表都不存在,请添加一列?的主要内容,如果未能解决你的问题,请参考以下文章
mysql中先判断数据是不是存在,如存在则增加数量,不存在则增加一条记录