从表中删除列

时间:2013-07-31 02:39:53

标签: sql sql-server

我正在尝试找出代码来生成循环通过表的内容并检查它是否仍然是有效列并删除所有无效的列。

declare @counter int
declare @col_count int
declare @col_name char(100)
declare @temp_sql char(100)
set @counter = 0

SELECT @col_count = COUNT(*) from sys.columns 
where Object_ID = Object_ID(N'test') 
AND name <> 'pk_test'

while @counter < @col_count
begin  
  with CTE as (
    select name, row_number() over (order by column_id) as ColNo
    from sys.columns where object_id = object_id('test') AND name <> 'pk_test'
  )
  select @col_name = name from CTE where ColNo = ((@counter) + 1)

  SET @temp_sql = 'ALTER TABLE test DROP column ' + @col_name + ';'
  EXECUTE (@temp_sql);

  set @counter = @counter + 1
end

由于某种原因EXECUTE导致代码跳过其他所有调用,但是如果我用注释取出执行并抛出一个打印,它将显示所有有效的drop语句。

我试过这样做:

SET @temp_sql = @temp_swl + 'ALTER TABLE test DROP column ' + @col_name
enter code here

我试图一次性组合所有的alter table,但它似乎不起作用。

我觉得我错过了一些小事!

2 个答案:

答案 0 :(得分:2)

您每次都使用计数器重新生成表格 - 除非您有时使用alter table语句删除一行(即列)。

相反,首先生成表,然后循环遍历它。所以,替换这个:

while @counter < @col_count
begin  
  with CTE as (
    select name, row_number() over (order by column_id) as ColNo
    from sys.columns where object_id = object_id('test') AND name <> 'pk_test'
  )
  select @col_name = name from CTE where ColNo = ((@counter) + 1)

  SET @temp_sql = 'ALTER TABLE test DROP column ' + @col_name + ';'
  EXECUTE (@temp_sql);

  set @counter = @counter + 1
end

有了这个:

declare @columns table (colnum int not null identity(1, 1), colname varchar(255));

insert into @columns(colname)
    select name
    from sys.columns
    where object_id = object_id('test') AND name <> 'pk_test';

set @col_count = max(colnum) from @columns;

while @counter < @col_count
begin  

  select @col_name = name from @columns where ColNo = ((@counter) + 1);

  SET @temp_sql = 'ALTER TABLE test DROP column ' + @col_name + ';'
  EXECUTE (@temp_sql);

  set @counter = @counter + 1;
end;

我不打算评论你在做什么,但这应该通过预先计算列列表来解决“跳过”问题。这样,列表不受alter table语句的影响。

答案 1 :(得分:1)

这是一种更简单的方法,它不需要游标(这是while循环的另一个名称),并且没有跳过任何东西的可能性。请注意,我假设“无效”表示“没有名称pk_test”。如果“无效”是指其他内容,请澄清。当然,您可能希望确保该表首先包含一个名为pk_test的列,否则最后一个ALTER将失败 - 您的代码当前不会检查该列。

DECLARE @t NVARCHAR(512), -- the table we're affecting
        @c SYSNAME;       -- the column we want to keep

SELECT @t = N'dbo.test', @c = N'pk_test';


IF EXISTS 
(
  SELECT 1 FROM sys.columns 
    WHERE [object_id] = OBJECT_ID(@t)
    AND name = @c
)
BEGIN

  DECLARE @sql NVARCHAR(MAX);

  SET @sql = N'';

  SELECT @sql = @sql + N'
    ALTER TABLE ' + @t + ' DROP COLUMN ' + QUOTENAME(name) + ';'
  FROM sys.columns WHERE [object_id] = OBJECT_ID(@t) AND name <> @c;

  PRINT @sql;
  -- EXEC sp_executesql @sql;
END
ELSE
BEGIN
  PRINT 'Sorry, can't delete all columns from ' + @t + '.';
END