0

我试图找出代码来生成遍历表内容的循环并检查它是否仍然是有效列并删除所有不再有效的列。

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

我试图一次合并所有的变更表,但它似乎不起作用。

我觉得我错过了一些小东西!

4

2 回答 2

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语句的影响。

于 2013-07-31T02:53:46.050 回答
1

这是一种更简单的方法,它不需要游标(这是 while 循环的另一个名称),并且没有可能跳过任何内容。请注意,我假设“无效”意味着“没有名称pk_test”。如果“无效”有其他含义,请澄清。当然,您可能希望确保该表有一个名为pk_testfirst 的列,否则最后一个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
于 2013-07-31T03:00:02.663 回答