如何在特定列之后在SQL中添加列?

时间:2011-10-28 18:17:49

标签: tsql alter-table

我有一张桌子:

MyTable
    ID
    FieldA
    FieldB

我想更改表并添加一列,如下所示:

MyTable
    ID
    NewField
    FieldA
    FieldB

在MySQL中我会这样做:

ALTER TABLE MyTable ADD COLUMN NewField int NULL AFTER ID;

一条线,漂亮,简单,效果很好。我如何在微软的世界中做到这一点?

10 个答案:

答案 0 :(得分:31)

不幸的是你不能。

如果你真的想按顺序使用它们,则必须按顺序创建一个包含列的新表并复制数据。或重命名列等。没有简单的方法。

答案 1 :(得分:6)

的解决方案:

这适用于对更改表没有依赖性的表,这些表会触发级联事件。 首先确保您可以删除要重组的表而不会产生任何灾难性的后果。 记下与表关联的所有依赖项和列约束(即触发器,索引)等)。完成后,您可能需要将它们重新放入。

第1步:创建临时表以保存要重组的表中的所有记录。不要忘记包含 新列

CREATE TABLE #tmp_myTable
(   [new_column] [int] NOT NULL, <-- new column has been inserted here!
    [idx] [bigint] NOT NULL,
    [name] [nvarchar](30) NOT NULL,
    [active] [bit] NOT NULL
)

第2步:确保已复制所有记录,并确保列结构符合您的要求。

SELECT TOP 10 * FROM #tmp_myTable ORDER BY 1 DESC - 您可以执行COUNT(*)或任何操作以确保复制所有记录

第3步: DROP原始表:

DROP TABLE myTable

如果您对可能发生的不良事件感到偏执,只需重命名原始表(而不是丢弃它)。通过这种方式,它可以随时返回。

EXEC sp_rename myTable, myTable_Copy

第4步:以您想要的方式重新创建表myTable(应匹配 #tmp_myTable 表结构)

CREATE TABLE myTable
(   [new_column] [int] NOT NULL,
    [idx] [bigint] NOT NULL,
    [name] [nvarchar](30) NOT NULL,
    [active] [bit] NOT NULL
)

- 不要忘记您可能需要的任何限制

第5步:将temp #tmp_myTable 表中的所有记录复制到新的(改进的)表 myTable

INSERT INTO myTable ([new_column],[idx],[name],[active])
SELECT [new_column],[idx],[name],[active]
FROM #tmp_myTable

第6步:检查所有数据是否都在新的改进表 myTable 中。如果是,请自行清理并删除临时表 #tmp_myTable myTable_Copy 表,如果您选择重命名而不是删除它。

答案 2 :(得分:3)

如果使用Management Studio中的GUI创建列,则应该能够执行此操作。我相信管理工作室实际上是在完全重建表格,这就是为什么会出现这种情况。

正如其他人所提到的,表中列的顺序无关紧要,如果确实如此,那么代码就会出现问题。

答案 3 :(得分:2)

  

/ *   用于更改表的列顺序的脚本
  请注意,这将创建一个新表来替换原始表
  但是,它不会复制触发器或其他表属性 - 只是数据
  * /

按照您需要的顺序生成一个包含列的新表

Select Column2, Column1, Column3 Into NewTable from OldTable

删除原始表格

Drop Table OldTable;

重命名新表

EXEC sp_rename 'NewTable', 'OldTable';

答案 4 :(得分:1)

您必须重建表格。幸运的是,列的顺序根本不重要!

观看我对列进行神奇的重新排序:

SELECT ID, Newfield, FieldA, FieldB FROM MyTable

之前有人问过这个问题。

答案 5 :(得分:1)

在Microsoft SQL Server Management Studio(MSSQL的管理工具)中,只需进入表格的“设计”并将列拖到新位置即可。不是命令行,但你可以这样做。

答案 6 :(得分:1)

即使问题陈旧,也需要有关Management Studio的更准确答案。

您可以手动或使用Management Studio创建列。但是Management Studio将需要重新创建表格,并且如果您已经有太多数据,将导致超时,除非表格很轻,否则请避免。

要更改列的顺序,您只需在Management Studio中移动它们即可。这不应要求(很可能存在异常)Management Studio重新创建表,因为它很可能会更改表定义中列的排序。

我已经在很多场合以这种方式完成了这些表格,由于其中的数据,我无法使用GUI添加列。然后使用Management Studio的GUI移动列并简单地保存它们。

你会从有保证的时间到等待几秒钟。

答案 7 :(得分:1)

在SQL Enterprise Management Studio中,打开表,将列添加到所需位置,然后 - 而不是保存更改 - 生成更改脚本。您可以在SQL中看到它是如何完成的。

简而言之,其他人所说的是对的。 SQL Management Studio将您的所有数据拉入临时表,删除表,使用正确顺序的列重新创建它,并将临时表数据放回其中。在特定位置添加列没有简单的语法。

答案 8 :(得分:0)

这绝对是可能的。虽然你不应该这样做,除非你知道你在处理什么。 我花了大约两天的时间来搞清楚。 这是一个存储过程,我输入: - -数据库名称 (架构名称为&#34; _&#34;为了便于阅读) ---表名 - -柱 ---列数据类型 (添加的列始终为null,否则您无法插入) ---新专栏的位置。

由于我使用SAM工具包中的表(其中一些有> 80列),因此典型变量无法包含查询。这迫使需要外部文件。现在要小心存储该文件以及谁有权访问NTFS和网络级别。

干杯!

USE [master]
GO
/****** Object:  StoredProcedure [SP_Set].[TrasferDataAtColumnLevel]    Script Date: 8/27/2014 2:59:30 PM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE PROCEDURE [SP_Set].[TrasferDataAtColumnLevel]
(
    @database varchar(100),
    @table varchar(100),
    @column varchar(100),
    @position int,
    @datatype varchar(20)    
)
AS
BEGIN
set nocount on
exec  ('
declare  @oldC varchar(200), @oldCDataType varchar(200), @oldCLen int,@oldCPos int
create table Test ( dummy int)
declare @columns varchar(max) = ''''
declare @columnVars varchar(max) = ''''
declare @columnsDecl varchar(max) = ''''
declare @printVars varchar(max) = ''''

DECLARE MY_CURSOR CURSOR LOCAL STATIC READ_ONLY FORWARD_ONLY FOR 
select column_name, data_type, character_maximum_length, ORDINAL_POSITION  from ' + @database + '.INFORMATION_SCHEMA.COLUMNS where table_name = ''' + @table + '''
OPEN MY_CURSOR FETCH NEXT FROM MY_CURSOR INTO @oldC, @oldCDataType, @oldCLen, @oldCPos WHILE @@FETCH_STATUS = 0 BEGIN

if(@oldCPos = ' + @position + ')
begin
    exec(''alter table Test add [' + @column + '] ' + @datatype + ' null'')
end

if(@oldCDataType != ''timestamp'')
begin

    set @columns += @oldC + '' , '' 
    set @columnVars += ''@'' + @oldC + '' , ''

    if(@oldCLen is null)
    begin
        if(@oldCDataType != ''uniqueidentifier'')
        begin
            set @printVars += '' print convert('' + @oldCDataType + '',@'' + @oldC + '')'' 
            set @columnsDecl += ''@'' + @oldC + '' '' + @oldCDataType + '', '' 
            exec(''alter table Test add ['' + @oldC + ''] '' + @oldCDataType + '' null'')
        end
        else
        begin
            set @printVars += '' print convert(varchar(50),@'' + @oldC + '')'' 
            set @columnsDecl += ''@'' + @oldC + '' '' + @oldCDataType + '', '' 
            exec(''alter table Test add ['' + @oldC + ''] '' + @oldCDataType + '' null'')
        end
    end
    else
    begin 
        if(@oldCLen < 0)
        begin
            set @oldCLen = 4000
        end
        set @printVars += '' print @'' + @oldC 
        set @columnsDecl += ''@'' + @oldC + '' '' + @oldCDataType + ''('' + convert(character,@oldCLen) + '') , '' 
        exec(''alter table Test add ['' + @oldC + ''] '' + @oldCDataType + ''('' + @oldCLen + '') null'')
    end
end

if exists (select column_name from INFORMATION_SCHEMA.COLUMNS where table_name = ''Test'' and column_name = ''dummy'')
begin
    alter table Test drop column dummy
end

FETCH NEXT FROM MY_CURSOR INTO  @oldC, @oldCDataType, @oldCLen, @oldCPos END CLOSE MY_CURSOR DEALLOCATE MY_CURSOR

set @columns = reverse(substring(reverse(@columns), charindex('','',reverse(@columns)) +1, len(@columns)))
set @columnVars = reverse(substring(reverse(@columnVars), charindex('','',reverse(@columnVars)) +1, len(@columnVars)))
set @columnsDecl = reverse(substring(reverse(@columnsDecl), charindex('','',reverse(@columnsDecl)) +1, len(@columnsDecl)))
set @columns = replace(replace(REPLACE(@columns, ''       '', ''''), char(9) + char(9),'' ''), char(9), '''')
set @columnVars = replace(replace(REPLACE(@columnVars, ''       '', ''''), char(9) + char(9),'' ''), char(9), '''')
set @columnsDecl = replace(replace(REPLACE(@columnsDecl, ''  '', ''''), char(9) + char(9),'' ''),char(9), '''')
set @printVars = REVERSE(substring(reverse(@printVars), charindex(''+'',reverse(@printVars))+1, len(@printVars))) 

create table query (id int identity(1,1), string varchar(max))

insert into query values  (''declare '' + @columnsDecl + ''
DECLARE MY_CURSOR CURSOR LOCAL STATIC READ_ONLY FORWARD_ONLY FOR '')

insert into query values   (''select '' + @columns + '' from ' + @database + '._.' + @table + ''')

insert into query values  (''OPEN MY_CURSOR FETCH NEXT FROM MY_CURSOR INTO '' + @columnVars + '' WHILE @@FETCH_STATUS = 0 BEGIN '')

insert into query values   (@printVars )

insert into query values   ( '' insert into Test ('')
insert into query values   (@columns) 
insert into query values   ( '') values ( '' + @columnVars + '')'')

insert into query values  (''FETCH NEXT FROM MY_CURSOR INTO  '' + @columnVars + '' END CLOSE MY_CURSOR DEALLOCATE MY_CURSOR'')

declare @path varchar(100) = ''C:\query.sql''
declare @query varchar(500) = ''bcp "select string from query order by id" queryout '' + @path + '' -t, -c -S  '' + @@servername +  '' -T''

exec master..xp_cmdshell @query

set @query  = ''sqlcmd -S '' + @@servername + '' -i '' + @path

EXEC xp_cmdshell  @query

set @query = ''del ''  + @path

exec xp_cmdshell @query

drop table ' + @database + '._.' + @table + '

select * into ' + @database + '._.' + @table + ' from Test 

drop table query
drop table Test  ')

END

答案 9 :(得分:0)

如果您使用GUI来执行此操作,则必须取消选择以下选项以允许删除表,

enter image description here

相关问题