将行从一个表移动到另一个表


9

作为归档过程的一部分,我正在将记录从一个数据库移动到另一个数据库。我想将这些行复制到目标表,然后从源表中删除相同的行。

我的问题是,在删除行之前检查第一个插入是否成功的最有效方法是什么?

我的想法是这样,但是我觉得有更好的方法:

@num_records=select count(ID) from Source_Table where (criteria for eligible rows)

insert * into Destination_Table where (criteria for eligible rows)

if ((select count(ID) from Destination_Table where (criteria) )=@numrecords)

delete * from Source_Table where (criteria)

将它与RAISERROR函数结合起来更好/可行吗?谢谢!

Answers:


13

我建议使用TRY / CATCH语法以及显式事务。我对此解决方案的假设是,插入失败的原因是某种可捕获的SQL错误(例如,键冲突,数据类型不匹配/转换错误等)。结构如下所示:

BEGIN TRAN

BEGIN TRY
  INSERT INTO foo(col_a,col_b,col_c,recdate)
  SELECT col_a,col_b,col_c,recdate
  FROM bar
  WHERE recdate BETWEEN @startdate AND @enddate

  DELETE FROM bar
  WHERE recdate BETWEEN @startdate AND @enddate

  COMMIT TRAN
END TRY
BEGIN CATCH
  ROLLBACK TRAN
END CATCH

如果INSERT或DELETE中发生任何错误,则此结构的工作方式将使整个操作回滚。这保证了整个动作必须成功完成。如果您认为有必要,可以将其与2012年的THROW或2008年及以后的RAISERROR结合使用,以添加其他逻辑,并在未满足该逻辑的情况下强制回滚。

另一个选择是查看SET XACT_ABORT ON,尽管我认为TRY / CATCH语法为您提供了更多的粒度。


19

如果您的存档表没有

  • 已启用已定义的触发器。
  • 参与FOREIGN KEY约束的任一侧。
  • 有检查约束或启用的规则。

您也可以在一个陈述中做到这一点。

DELETE FROM source_table
OUTPUT deleted.Foo,
       deleted.Bar,
       SYSUTCDATETIME()
INTO archive_table(Foo, Bar, archived)
WHERE  Foo = 1; 

这将作为一个整体成功或失败,也避免了可能出现的争用情况,因为在INSERT存档之间添加了行,并且DELETE(尽管您的WHERE子句很可能使这种情况变得极不可能)。


以上都不是。我想我可以走那条路,我喜欢代码极简主义。如果由于任何原因插入失败,我只是不想丢失记录。(即:表锁定,超时等)谢谢!
Dina 2013年

@Dina-您是否指出该OUTPUT子句可能实现?不是因为这只是一个陈述。还避免了必须读取两次行的问题(并且可能丢失丢失的行,该行在插入的读取和删除的读取之间添加)
Martin Smith

是的,这就是我的意思。谢谢,我明白你的意思。
Dina 2013年

FWIW-此方法将导致日志文件的增长接近原始表的大小。确保可以忍受。如果不能,请使用DELETE TOP(N)和一个检查@@ rowcount变量的While循环将其分为几批。
Wjdavis16年

1

我考虑进行归档的方法(我肯定也不是很完美)是在新归档表中添加一个位列,例如“ Archived”,在成功传输记录后,其值为1。并且,一旦传输了所有记录,就可以执行删除操作,同时还要从存档表中查找此“ Archived”字段值“ 1”,即True。

我同意Mike使用Try / Catch。


1

尝试这个:

INSERT dbo.newtable(
      name,
      department,
      Salary
) SELECT 
            name,
            FirstName,
            Lastname
      FROM    (
           DELETE dbo.oldtable
           OUTPUT
                   DELETED.name,
                   DELETED.department,
                   DELETED.Salary
           WHERE ID  IN ( 1001, 1003, 1005 )
      ) AS RowsToMove;

SELECT * FROM dbo.newtable;
SELECT * FROM dbo.oldtable;
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.