【问题标题】:Copy table row by row逐行复制表格
【发布时间】:2011-01-28 09:48:50
【问题描述】:

我正在做一些触发器性能优化,我想对其进行测试。我有一个实际触发器和一个修改后的触发器,我想在真实数据上对旧触发器和新触发器进行测试并进行比较。我想将表 A 逐行复制到 A_BCK。表 A 大约有 60 列和 4000 行,所以我的触发器将被执行 4000 次,我可以将它用于性能测试。

我读过游标,但不知道如何使用游标和变量进行逐行复制(不是选择到 a_bck 或插入到 a_bck 中,从 a 中选择都只生成一个插入)。

我的行复制过程现在看起来像这样:

declare @actualrow varchar(15);

DECLARE eoauz CURSOR FAST_FORWARD FOR SELECT * FROM A

open eoauz
fetch next from eoauz into @actualrow
while @@fetch_status = 0
begin
 /* INSERT INTO A_BCK VALUES FROM @actualrow  */
fetch next from eoauz into @actualrow
end
close eoauz
deallocate eoauz

这当然行不通。我需要类似行变量的东西,而不是 varchar。有人可以帮助我完成任务吗?

【问题讨论】:

  • 为什么要逐行做这个? MSSQL 是基于集合的。避免使用光标,尤其是在触发器中 - 除非您喜欢生活在痛苦的世界中。
  • 我不这样做 in 我的触发器。我想这样做是为了测试我的触发器。我需要一种方法来对真实数据执行触发器。
  • 嗯,如果您将 ` 删除到 @actualrow` 位,它会将整行返回给客户端。我不确定是否有以某种方式将该行插入另一个表的语法。
  • @cyberkiwi - 我的答案应该适用于电视。

标签: sql sql-server tsql insert cursor


【解决方案1】:

我不经常使用游标,所以我可能缺少一种更直接的方法......

SELECT TOP 0 *
INTO   #t
FROM   master..spt_values /*Create an empty table of correct schema*/

DECLARE eoauz CURSOR FAST_FORWARD FOR
  SELECT *
  FROM   master..spt_values

OPEN eoauz

INSERT INTO #t
EXEC ('fetch next from eoauz')

WHILE @@FETCH_STATUS = 0
  INSERT INTO #t
  EXEC ('fetch next from eoauz')

CLOSE eoauz

DEALLOCATE eoauz

SELECT *
FROM   #t

DROP TABLE #t

【讨论】:

  • 真可惜。我搞砸了投票,不能再投票赞成这个答案了。我所做的是我赞成它,然后迅速收回我的投票,首先检查该方法是否有效。它有。现在我试图再次投票,但它一直说我的投票现在被锁定,直到答案被编辑。真的这么固执吗?您的答案似乎不需要任何实质性修改,除非您想在最后添加一个几乎毫无意义的 select * from #t (无论如何,您的示例只是一个测试)。否则,这正是我的想法。因此,一个应有的赞成票正在等待中。
  • @Andriy - 谢谢!我已经进行了建议的更改。
  • 还有+1。 (aside)我想知道在可能的情况下投票阻止是一个问题还是一个功能......
【解决方案2】:

以下代码的示例表

create table A(ID INT IDENTITY, a int, b int)
create table B(ID INT, a int, b int)
insert A select 1,2 union all select 3,4 union all select 5,6

每列都需要一个变量。请参阅下面的示例

declare @id int, @a int, @b int
DECLARE eoauz CURSOR FAST_FORWARD FOR SELECT * FROM A
open eoauz
fetch next from eoauz into @id, @a, @b
while @@fetch_status = 0
begin
 INSERT B VALUES( @id, @a, @b )
fetch next from eoauz into @id, @a, @b
end
close eoauz
deallocate eoauz

我不喜欢使用游标,而是尽可能使用 WHILE 循环

declare @id int
select top 1 @id = id from A order by ID
while @@ROWCOUNT > 0 begin
    insert B select * from A where ID=@id  -- one row
    select top 1 @id = id from A where id > @id order by ID
end

【讨论】:

  • 感谢您的回答。我不喜欢的是我有 60 列,所以我必须声明 60 个变量。此外,我希望光标仅用于测试。我在生产数据库中没有任何游标。所以大家真的不用担心我会在生产中使用它;-)
  • @Robert - 查看使用一列(键)返回表的 while 循环替代方案(也可以在光标上工作)
【解决方案3】:

我会将表的主键选择到游标变量中。这唯一地标识了一行,然后您可以轻松地选择:

declare @pk varchar(15);

DECLARE eoauz CURSOR FAST_FORWARD FOR SELECT PK FROM A

open eoauz
fetch next from eoauz into pk
while @@fetch_status = 0
begin
INSERT INTO A_BCK select * from A where PK = @pk
fetch next from eoauz into pk
end
close eoauz
deallocate eoauz

我认为这种方法的一个很大的优势是易于理解和阅读。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-08-08
    • 2014-04-30
    • 1970-01-01
    • 1970-01-01
    • 2015-10-30
    • 2017-08-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多