Satırları bir tablodan diğerine taşıma


9

Arşivleme sürecinin bir parçası olarak kayıtları bir veritabanından diğerine taşıyorum. Hedef tabloya satırları kopyalamak ve sonra kaynak tablodan aynı satırları silmek istiyorum.

Benim sorum, satırları silmeden önce ilk eklemenin başarılı olup olmadığını kontrol etmenin en etkili yolu nedir.

Benim fikrim bu, ama daha iyi bir yol olduğunu hissediyorum:

@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 işleviyle birleştirmek daha iyi / mümkün mü? Teşekkür ederim!

Yanıtlar:


13

Açık işlemler ile birlikte TRY / CATCH sözdizimini tavsiye ederim . Bu çözüm için benim varsayım, ekleme hatası nedeni bir tür yakalanabilir SQL hatası (bir anahtar ihlali, veri türü uyuşmazlığı / dönüşüm hatası, vb.) Olmasıdır. Yapı şöyle görünecektir:

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

Bu yapının çalışma şekli, INSERT veya DELETE öğesinde herhangi bir hata oluşursa, tüm eylem geri alınır. Bu, tüm eylemin tamamlanması için başarılı olması gerektiğini garanti eder. Gerekli olduğunu düşünüyorsanız, ek mantık eklemek ve bu mantık karşılanmadığında geri dönüşü zorlamak için onu 2012 için THROW veya 2008'de RAISERROR ile birleştirebilirsiniz .

Başka bir seçenek SET XACT_ABORT ON bakmak olsa da, ben TRY / CATCH sözdizimi size daha fazla ayrıntı verir hissediyorum.


19

Arşiv tablonuz yoksa .

  • Üzerinde tanımlanan tetikleyicileri etkinleştirdiniz.
  • Bir FOREIGN KEY kısıtlamasının her iki tarafına katılın.
  • CHECK kısıtlamalarına veya etkin kurallara sahip olun.

Bunu aynı zamanda bir statenentte de yapabilirsiniz.

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

Bu, bir ünite olarak başarılı olur veya başarısız olur ve ayrıca INSERTarşivi arasına satırlar eklenerek olası yarış koşullarından kaçınır ve DELETE( WHEREcümleniz bunu son derece olası hale getirebilir).


Yukarıdakilerin hiçbiri. Sanırım o rotaya gidebilirim, kod minimalizminden hoşlanıyorum. Ekleme herhangi bir nedenle başarısız olursa kayıtları kaybetmek istemiyorum. (yani: masa kilitleme, zaman aşımı vb.) Teşekkürler!
Dina

@Dina - Maddenin bunun mümkün olduğunu OUTPUTmu söylüyorsunuz ? Hepsi tek bir ifade olduğu için değil. Ayrıca, satırları iki kez okumak zorunda kalmama sorununu (ve muhtemelen ekleme için okuma ile silme için okuma arasında eklenen satırları kaybetme) sorunu önler
Martin Smith

Evet, demek istediğim buydu. Teşekkürler, ne demek istediğini anlıyorum.
Dina

FWIW - bu yöntem, orijinal tablonun boyutuna yakın günlük dosyası büyümesine neden olur. Bununla yaşayabileceğinden emin ol. Yapamıyorsanız, DELETE TOP (N) ve @@ rowcount değişkenini kontrol eden bir While döngüsüyle toplu olarak bölün.
Wjdavis5

1

Arşivleme yapmayı düşündüğüm yol (mükemmel olmadığından eminim), yeni arşiv tablosuna 'Arşivlendi' gibi bir kaydın başarılı bir şekilde aktarılmasından sonra 1 değerine sahip olacak bir sütun eklemektir. Ve tüm kayıtları aktardıktan sonra, arşivlenmiş tablodan '1' yani 'True' alanın bu 'Arşivlenmiş' alan değerini ararken bir silme işlemi gerçekleştirebilirsiniz.

Ve Mike ile Try / Catch kullanma konusunda hemfikirim.


1

Bunu dene:

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;
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.