将数据从一个 table 复制到另一个时,如何避免时间戳插入错误?
How can I avoid a timestamp insert error when copying data from one table to another?
我正在尝试根据主键在 table 列表 (~30) 中剔除数据。
我的方法是:
1.Create 一个中间体 table 并为每个 table
加载所需的数据
2.Truncate原table
3.Insert数据从中间table变回原来的table.
这是我目前使用的代码:
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.
因此,该错误告诉我无法将任何内容插入时间戳列。
为了避免 selecting 时间戳,我需要避免 selecting 它(即使用 select *)。
是否有一种简单的方法 selecting 除时间戳类型之外的所有列,或者我是否需要进入信息模式并为每个 table 构建一个动态 select 语句]?
(或者隐含的问题,有没有更好的方法来做我想做的事情?)
谢谢
怎么样
delete from TABLE where P_ID not in( select P_ID from pc_table )
?
简短的回答是您需要将 '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
这不是有史以来最漂亮的东西,但它确实有效。
希望这可以帮助 运行 遇到此问题的其他人。
如果是数百万行,而不是数十亿行,那么简单
DELETE from TABLE where P_ID not in (select P_ID from pc_table)
(可能是分批)可能acceptable。首先删除所有索引(ID
上的主键除外)和约束,删除行,重新创建索引。更好的是,不是删除,而是禁用索引,然后使用 REBUILD INDEX
.
重新启用它们
还有一件事需要考虑。如果您确实使用中间 table,那么在重新插入后 timestamp
列的所有值都会变得不同。如果您不关心保留此列中的值,您可以在处理之前简单地删除此列,并在完成所有操作后将其添加回来。
如果性能很重要,您应该以您选择的任何方法禁用目标 table 上的约束和索引。
这给我们带来了另一种方法:
SELECT * INTO intermediate_table ...
适用于 timestamp
列。
是
INSERT INTO final_table SELECT * FROM intermediate_table ...
这不适用于时间戳列。
因此,您可以 DROP final_table
而不是 TRUNCATE final_table
,并且还可以 SELECT * INTO final_table ...
第二次。
因此您也可以保留 timestamp
列的值。当然,如果你完全 DROP
它,你将不得不重新创建原始 table 的所有约束和索引。
我正在尝试根据主键在 table 列表 (~30) 中剔除数据。
我的方法是:
1.Create 一个中间体 table 并为每个 table
加载所需的数据
2.Truncate原table
3.Insert数据从中间table变回原来的table.
这是我目前使用的代码:
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.
因此,该错误告诉我无法将任何内容插入时间戳列。
为了避免 selecting 时间戳,我需要避免 selecting 它(即使用 select *)。
是否有一种简单的方法 selecting 除时间戳类型之外的所有列,或者我是否需要进入信息模式并为每个 table 构建一个动态 select 语句]?
(或者隐含的问题,有没有更好的方法来做我想做的事情?)
谢谢
怎么样
delete from TABLE where P_ID not in( select P_ID from pc_table )
?
简短的回答是您需要将 '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
这不是有史以来最漂亮的东西,但它确实有效。
希望这可以帮助 运行 遇到此问题的其他人。
如果是数百万行,而不是数十亿行,那么简单
DELETE from TABLE where P_ID not in (select P_ID from pc_table)
(可能是分批)可能acceptable。首先删除所有索引(ID
上的主键除外)和约束,删除行,重新创建索引。更好的是,不是删除,而是禁用索引,然后使用 REBUILD INDEX
.
还有一件事需要考虑。如果您确实使用中间 table,那么在重新插入后 timestamp
列的所有值都会变得不同。如果您不关心保留此列中的值,您可以在处理之前简单地删除此列,并在完成所有操作后将其添加回来。
如果性能很重要,您应该以您选择的任何方法禁用目标 table 上的约束和索引。
这给我们带来了另一种方法:
SELECT * INTO intermediate_table ...
适用于 timestamp
列。
是
INSERT INTO final_table SELECT * FROM intermediate_table ...
这不适用于时间戳列。
因此,您可以 DROP final_table
而不是 TRUNCATE final_table
,并且还可以 SELECT * INTO final_table ...
第二次。
因此您也可以保留 timestamp
列的值。当然,如果你完全 DROP
它,你将不得不重新创建原始 table 的所有约束和索引。