Переміщення рядків від однієї таблиці до іншої


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? Дякую!

Відповіді:


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

Те, як ця структура працює, якщо виникає помилка в ВСТАВКІ або ВИДАЛЕННІ, вся дія повертається назад. Це гарантує, що вся дія повинна бути успішною для її завершення. Якщо ви вважаєте, що це необхідно, ви можете комбінувати його з THROW за 2012 рік або RAISERROR у 2008 році та попереднім, щоб додати додаткову логіку та примусити відкат, якщо ця логіка не була дотримана.

Іншим варіантом є перегляд SET XACT_ABORT ON , хоча я відчуваю, що синтаксис TRY / CATCH надає вам більше деталізації.


19

Якщо ваша архівна таблиця не відповідає .

  • Увімкнули визначені на ньому тригери.
  • Беріть участь з обох сторін обмеження ЗОВНІШНЯ КЛЮЧА.
  • Мати обмеження чи перевірити правила.

Ви також можете це зробити в одному штаті.

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

Це може бути успішним або невдалим як одиниця, а також уникне можливих умов перегонів із додаванням рядків між INSERTархівами та DELETE(хоча ваш WHEREпункт все одно може зробити це надзвичайно малоймовірним).


Жоден з перерахованих вище. Я думаю, що я міг би піти цим маршрутом, мені подобається мінімалізм коду. Я просто не хочу втрачати записи, якщо вставка не вдається з будь-якої причини. (тобто: блокування таблиці, тайм-аути та ін.) Дякую!
Діна

@Dina - Ви вказували, що це можливо за допомогою OUTPUTпункту? Це не тому, що це все одне твердження. Також уникає проблеми читання рядків двічі (і, можливо, втрати рядків, доданих між читанням для вставки та читанням для видалення)
Мартін Сміт

Так, це я мав на увазі. Дякую, я бачу вашу думку.
Діна

FWIW - цей метод призведе до зростання журналу файлів, близького до розміру вихідної таблиці. Переконайтеся, що ви можете з цим жити. Якщо ви не можете, розбийте його на партії DELETE TOP (N) та циклом while, який перевіряє змінну @@ rowcount.
Wjdavis5

1

Те, як я думав про архівацію (я впевнений, що це не ідеально), - це додати трохи стовпчика до нової таблиці архіву, як-от "Архівований", який матиме значення 1 після успішної передачі запису. І як тільки ви перенесите всі записи, ви можете виконати операцію з видалення, шукаючи також значення цього поля «Заархівоване» значення «1», тобто True з архівованої таблиці.

І я погоджуюся з Майком щодо використання 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;
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.