【问题标题】:T-SQL: alter table to add a column that exists in another tableT-SQL:alter table 添加一个存在于另一个表中的列
【发布时间】:2015-07-20 10:44:02
【问题描述】:

我正在使用 SQL Server 2008 中的两个表:foofoo_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 语句?

谢谢!

【问题讨论】:

    标签: sql sql-server sql-server-2008 alter-table


    【解决方案1】:

    我倾向于在这里使用目录视图而不是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;
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-08-18
      • 1970-01-01
      相关资源
      最近更新 更多