我正在使用SQL Server 2008中的两个表:foo
和foo_mod
,它们具有以下架构:
CREATE TABLE foo
(
[bar] DATETIME NULL ,
[bar1] VARCHAR(20) NULL ,
[different_column] VARCHAR(50) NOT NULL
)
CREATE TABLE foo_mod
(
[bar] DATETIME NULL ,
[bar1] VARCHAR(20) NULL
)
我想构建一个SQL脚本来实现以下功能:
对于foo
的每一列,检查foo_mod
中是否存在该列,如果不存在,请更改foo_mod
以添加缺少的列。
在此示例中,我的脚本将返回以下内容:
IF COL_LENGTH('foo_mod','bar') IS NULL BEGIN
ALTER TABLE foo_mod
ADD bar DATETIME NULLL;
END
IF COL_LENGTH('foo_mod','bar1') IS NULL BEGIN
ALTER TABLE foo_mod
ADD bar1 VARCHAR(20) NULL;
END
IF COL_LENGTH('foo_mod','different_column') IS NULL BEGIN
ALTER TABLE foo_mod
ADD different_column VARCHAR(50) NOT NULL;
END
现在我的脚本使用游标循环遍历第一个表中的INFORMATION_SCHEMA.COLUMNS
:
DECLARE @column_name VARCHAR(max);
DECLARE @is_nullable VARCHAR(3);
DECLARE @data_type NVARCHAR(128);
DECLARE @default NVARCHAR(4000);
DECLARE @max_lengh INT;
DECLARE @sql VARCHAR(max);
DECLARE @output VARCHAR(max);
SET @output = '';
DECLARE col_names_cursor CURSOR
FOR
SELECT COLUMN_NAME, IS_NULLABLE, DATA_TYPE, COLUMN_DEFAULT, CHARACTER_MAXIMUM_LENGTH
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = N'foo'
OPEN col_names_cursor
FETCH NEXT FROM col_names_cursor INTO @column_name, @is_nullable, @data_type,@default, @max_lengh;
WHILE @@FETCH_STATUS = 0
BEGIN
SET @sql = 'IF COL_LENGTH(''foo_mod'','''@column_name''') IS NULL BEGIN ALTER TABLE ''foo_mod'' ADD '
SET @sql += ? -- build sql script from informations
FETCH NEXT FROM col_names_cursor INTO @column_name, @is_nullable, @data_type,@default, @max_lengh;
END
CLOSE col_names_cursor;
DEALLOCATE col_names_cursor;
是否有一种简单的方法可以从给定的信息构建SQL语句?
谢谢!
答案 0 :(得分:2)
我倾向于使用此处的目录视图而不是INFORMATION_SCHEMA
,因为INFORMATION_SCHEMA
不处理标识列或计算列:
为了表明这一点,我稍微改变了你的表格foo
:
CREATE TABLE foo
(
ID INT IDENTITY(1, 1),
[bar] DATETIME NULL ,
[bar1] VARCHAR(20) NULL ,
[different_column] VARCHAR(50) NOT NULL ,
ComputedColumn AS bar1 + different_column
)
然后,您可以查询目录视图以构建语句:
SELECT 'ALTER TABLE dbo.Foo_mod ADD ' + c.Name + ' ' +
CASE WHEN c.is_computed = 1 THEN 'AS ' + cc.definition
ELSE t.Name +
CASE WHEN c.is_identity = 1
THEN ' IDENTITY(' + CONVERT(VARCHAR(10), ic.seed_value) + ',' + CONVERT(VARCHAR(10), ic.increment_value) + ')'
WHEN t.name IN ('CHAR', 'NCHAR', 'VARCHAR', 'NVARCHAR', 'DATETIME2')
THEN '(' + CONVERT(VARCHAR(10), c.max_length) + ')'
WHEN t.name IN ('NUMERIC', 'DECIMAL')
THEN '(' + CONVERT(VARCHAR(10), c.precision) + ', ' + CONVERT(VARCHAR(10), c.scale) + ')'
ELSE ''
END
END + ';
GO
'
FROM sys.columns AS c
INNER JOIN sys.types AS t
ON t.system_type_id = c.system_type_id
AND t.user_type_id = c.user_type_id
LEFT JOIN sys.computed_columns AS cc
ON cc.object_id = c.object_id
AND cc.column_id = c.column_id
LEFT JOIN sys.identity_columns AS ic
ON ic.object_id = c.object_id
AND ic.column_id = c.column_id
WHERE c.object_id = OBJECT_ID(N'dbo.foo', 'U')
AND NOT EXISTS
( SELECT 1
FROM sys.columns AS c2
WHERE c2.object_id = OBJECT_ID(N'dbo.foo_mod')
AND c2.name = c.name
)
ORDER BY c.column_id;
生成:
ALTER TABLE dbo.Foo_mod ADD ID int IDENTITY(1,1);
GO
ALTER TABLE dbo.Foo_mod ADD different_column varchar(50);
GO
ALTER TABLE dbo.Foo_mod ADD ComputedColumn AS ([bar1]+[different_column]);
GO
现在您需要做的就是通过concatenating the rows into a single row将其捕获到一个变量中,然后执行它:
DECLARE @SQL NVARCHAR(MAX);
SELECT @SQL = (SELECT 'ALTER TABLE dbo.Foo_mod ADD ' + c.Name + ' ' +
CASE WHEN c.is_computed = 1 THEN 'AS ' + cc.definition
ELSE t.Name +
CASE WHEN c.is_identity = 1
THEN ' IDENTITY(' + CONVERT(VARCHAR(10), ic.seed_value) + ',' + CONVERT(VARCHAR(10), ic.increment_value) + ')'
WHEN t.name IN ('CHAR', 'NCHAR', 'VARCHAR', 'NVARCHAR', 'DATETIME2')
THEN '(' + CONVERT(VARCHAR(10), c.max_length) + ')'
WHEN t.name IN ('NUMERIC', 'DECIMAL')
THEN '(' + CONVERT(VARCHAR(10), c.precision) + ', ' + CONVERT(VARCHAR(10), c.scale) + ')'
ELSE ''
END
END + ';
GO
'
FROM sys.columns AS c
INNER JOIN sys.types AS t
ON t.system_type_id = c.system_type_id
AND t.user_type_id = c.user_type_id
LEFT JOIN sys.computed_columns AS cc
ON cc.object_id = c.object_id
AND cc.column_id = c.column_id
LEFT JOIN sys.identity_columns AS ic
ON ic.object_id = c.object_id
AND ic.column_id = c.column_id
WHERE c.object_id = OBJECT_ID(N'dbo.foo', 'U')
AND NOT EXISTS
( SELECT 1
FROM sys.columns AS c2
WHERE c2.object_id = OBJECT_ID(N'dbo.foo_mod')
AND c2.name = c.name
)
ORDER BY c.column_id
FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)');
PRINT @SQL;
EXECUTE sp_executesql @SQL;