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

Din*_*ina 9 sql-server-2012

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

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

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

@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)
Run Code Online (Sandbox Code Playgroud)

将它与 RAISERROR 功能结合是否更好/可能?谢谢!

Mar*_*ith 19

如果您的存档表没有

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

你也可以在一份声明中做到这一点。

DELETE FROM source_table
OUTPUT deleted.Foo,
       deleted.Bar,
       SYSUTCDATETIME()
INTO archive_table(Foo, Bar, archived)
WHERE  Foo = 1; 
Run Code Online (Sandbox Code Playgroud)

这将作为一个单元成功或失败,并且还避免了可能的竞争条件,因为在INSERT存档和之间添加了行DELETE(尽管您的WHERE子句很可能使这种情况变得极不可能)。


Mik*_*Fal 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
Run Code Online (Sandbox Code Playgroud)

这种结构的工作方式是,如果 INSERT 或 DELETE 中发生任何错误,整个操作都会回滚。这保证了整个动作必须成功完成。如果您觉得有必要,您可以将其与2012 年的THROW或2008 年及之前的RAISERROR结合起来,以添加额外的逻辑并在不满足该逻辑的情况下强制回滚。

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