Копировать таблицу построчно

Я занимаюсь оптимизацией производительности триггера и хочу протестировать ее. У меня есть фактический триггер и модифицированный триггер, и я хочу на реальных данных запустить тест на старом триггере и новом триггере и сравнить их. Я хочу скопировать таблицу 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. Может кто-нибудь помочь, как выполнить мою задачу?


person Robert Niestroj    schedule 28.01.2011    source источник
comment
Почему делают это ряд за рядом? MSSQL устанавливается на основе. Избегайте использования курсоров, особенно в триггерах, если только вам не нравится жить в мире боли.   -  person codingbadger    schedule 28.01.2011
comment
Я не делаю этого в своем триггере. Я хочу сделать это, чтобы проверить свой триггер. Мне нужен способ выполнить мой триггер на реальных данных.   -  person Robert Niestroj    schedule 28.01.2011
comment
Хм, если вы удалите бит `in @actualrow`, он вернет всю строку обратно клиенту. Я не уверен, есть ли синтаксис для вставки этой строки в другую таблицу.   -  person Martin Smith    schedule 28.01.2011
comment
@Martin - Нет, не в табличную переменную: social.msdn.microsoft.com/Forums/en-US/transactsql/thread/   -  person RichardTheKiwi    schedule 28.01.2011
comment
@cyberkiwi - Мой ответ должен работать с телевизором.   -  person Martin Smith    schedule 28.01.2011
comment
@Martin - никогда не думал передать его через EXEC. Неплохо   -  person RichardTheKiwi    schedule 28.01.2011


Ответы (3)


Я не часто работаю с курсорами, поэтому может быть более простой способ, который мне не хватает...

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
person Martin Smith    schedule 28.01.2011
comment
Какая жалость. Я испортил голосование и больше не могу голосовать за этот ответ. Что я сделал, так это проголосовал за него, а затем быстро отозвал свой голос, чтобы сначала проверить, работает ли метод. И это так. Теперь я снова пытаюсь проголосовать за него, но он продолжает говорить, что мой голос теперь заблокирован, пока ответ не будет отредактирован. Неужели так упрямо? Ваш ответ, похоже, не нуждается в каких-либо существенных изменениях, если только вы не захотите добавить почти бессмысленный select * from #t в конце (ваш пример в любом случае является просто тестом). В противном случае, это моя мысль точно. Итак, должное голосование ожидается. - person Andriy M; 28.01.2011
comment
@Андрей - Спасибо! Я внес предложенное изменение. - person Martin Smith; 28.01.2011
comment
И идет +1. (в сторону) Интересно, может ли блокировка голосования быть проблемой или особенностью... - person Andriy M; 28.01.2011

Пример таблицы для кода ниже

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
person RichardTheKiwi    schedule 28.01.2011
comment
Спасибо за ответ. Что мне не нравится, так это то, что у меня 60 столбцов, поэтому мне нужно объявить 60 переменных. Кроме того, я хочу, чтобы курсор использовался только для тестирования. У меня нет курсоров в рабочей БД. Так что, ребята, не бойтесь, что я буду использовать его в продакшене ;-) - person Robert Niestroj; 28.01.2011
comment
@Robert - посмотрите альтернативу цикла while (которая также может работать с курсором), используя один столбец (ключ), чтобы вернуться к таблице - person RichardTheKiwi; 28.01.2011

Я бы выбрал первичный ключ вашей таблицы в переменную курсора. Это однозначно идентифицирует одну строку, которую затем можно легко выбрать:

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

Я думаю, что этот метод имеет большое преимущество в том, что его легко понять и прочитать.

person dataduck    schedule 28.01.2011