2

我正在尝试根据主键在表列表(~30)中剔除数据。

我的方法是: 1.创建一个中间表并为每个表加载所需的数据
2.截断原始表
3.将中间表中的数据插入到原始表中。

这是我到目前为止使用的代码:

declare @table nvarchar(max) 
open tab
fetch next from tab into @table
while(@@FETCH_STATUS = 0)
       begin
              print @table
             exec ('select * into ' +@table+'_intermediate from '+@table+' where P_ID in( select P_ID from pc_table )')
             exec ('truncate table '+@table)
             exec ('insert into '+@table+' select * from '+@table+'_intermediate')
             exec ('drop table '+@table+'_intermediate') 
            fetch next from tab into @table
       end
close tab
deallocate tab

我遇到了一个错误:

Cannot insert an explicit value into a timestamp column. 
Use INSERT with a column list to exclude the timestamp column, 
or insert a DEFAULT into the timestamp column.

因此,该错误告诉我无法在时间戳列中插入任何内容。

为了避免选择时间戳,我需要避免选择它(即使用select *)。

是否有一种简单的方法可以选择除类型时间戳之外的所有列,还是我需要进入信息模式并为每个表构建动态选择语句?

(或隐含的问题,有没有更好的方法来做我想做的事情?)

谢谢

4

3 回答 3

1

简短的回答是,您需要在任何有时间戳列的位置放置“null”。

我制作了这个小脚本来创建列列表,以便将该列表放入 DML 语句中:

         declare @sel_statement nvarchar(max)=''
         declare @col nvarchar(100) =''
         declare @num_rows int =0
         declare @dat_type nvarchar(30)

         declare cols cursor for
         select column_name, data_type 
         from information_schema.COLUMNS
         where TABLE_NAME = @table  --uses table fetched from tab cursor

         open cols

         fetch next from cols into @col, @dat_type
         while(@@FETCH_STATUS = 0)
                begin
                set @num_rows +=1
                if @dat_type = 'timestamp'
                     set @sel_statement += 'null'
                else  
                      set @sel_statement += @col 
                fetch next from cols into @col, @dat_type
                if @@FETCH_STATUS=0
                      set @sel_statement += ','
                end
         close cols
         deallocate cols 

这不是有史以来最漂亮的东西,但它确实有效。

希望如果他们遇到这个问题,这可以帮助其他人。

于 2015-02-02T22:04:12.983 回答
1

如果是数百万行,而不是数十亿行,那么简单

DELETE from TABLE where P_ID not in (select P_ID from pc_table)

(可能分批)可能是可以接受的。首先删除所有索引(除了主键 on ID)和约束,删除行,重新创建索引。更好的是,不要删除,而是禁用索引,然后使用REBUILD INDEX.

还有一件事要考虑。如果您确实使用了中间表,那么在重新插入之后,timestamp列的所有值都会变得不同。如果您不关心在此列中保留值,您可以简单地在处理之前删除此列并在完成后将其添加回来。

如果性能很重要,您应该以您选择的任何方法禁用目标表上的约束和索引。

这给我们带来了另一种方法:

SELECT * INTO intermediate_table ...

适用于timestamp列。

这是

INSERT INTO final_table SELECT * FROM intermediate_table ...

这不适用于时间戳列。

所以,不是TRUNCATE final_table你也可以DROP final_tableSELECT * INTO final_table ...第二次。

因此,您也可以保留timestamp列的值。当然,如果你完全完成DROP它,你将不得不重新创建原始表的所有约束和索引。

于 2015-02-03T03:41:13.947 回答
0

怎么样

delete from TABLE where P_ID not in( select P_ID from pc_table )

?

于 2015-01-26T18:46:14.293 回答