Memindahkan baris dari satu tabel ke tabel lainnya

9

Saya memindahkan catatan dari satu database ke yang lain, sebagai bagian dari proses pengarsipan. Saya ingin menyalin baris ke tabel tujuan dan kemudian menghapus baris yang sama dari tabel sumber.

Pertanyaan saya adalah, apa cara paling efisien untuk melakukan pemeriksaan jika insert pertama berhasil sebelum menghapus baris.

Gagasan saya adalah ini, tetapi saya merasa ada cara yang lebih baik:

@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)

Apakah lebih baik / mungkin untuk menggabungkannya dengan fungsi RAISERROR? Terima kasih!

Dina
sumber

Jawaban:

13

Saya akan merekomendasikan sintaks TRY / CATCH bersama dengan transaksi eksplisit. Asumsi saya untuk solusi ini adalah bahwa alasan kegagalan memasukkan adalah semacam kesalahan SQL yang dapat dijebak (seperti pelanggaran utama, kesalahan data / kesalahan konversi, dll.). Strukturnya akan terlihat seperti ini:

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

Cara struktur ini bekerja, jika ada kesalahan yang terjadi di INSERT atau DELETE, seluruh tindakan akan dibatalkan. Ini menjamin bahwa seluruh tindakan harus berhasil diselesaikan. Jika Anda merasa bahwa hal itu perlu, Anda bisa menggabungkannya dengan THROW untuk 2012 atau RAISERROR pada tahun 2008 dan sebelumnya untuk menambahkan logika tambahan dan memaksa rollback jika logika yang tidak terpenuhi.

Pilihan lain adalah melihat SET XACT_ABORT AKTIF , meskipun saya merasa bahwa sintaks TRY / CATCH memberi Anda lebih banyak rincian.

Mike Fal
sumber
19

Jika tabel arsip Anda tidak .

  • Telah mengaktifkan pemicu yang ditentukan di atasnya.
  • Berpartisipasilah di kedua sisi batasan KUNCI ASING.
  • Miliki PERIKSA kendala atau aturan yang diaktifkan.

Anda juga bisa melakukannya dalam satu statenent.

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

Ini akan berhasil atau gagal sebagai satu unit dan juga menghindari kemungkinan kondisi balapan dengan baris ditambahkan di antara INSERTke arsip dan DELETE(meskipun WHEREklausa Anda mungkin membuat ini sangat tidak mungkin).

Martin Smith
sumber
Bukan dari salah satu di atas. Saya kira saya bisa pergi rute itu, saya suka kode minimalis. Saya hanya tidak ingin kehilangan catatan jika insert gagal karena alasan apa pun. (Yaitu: penguncian meja, batas waktu, dll) Terima kasih!
Dina
@Dina - Apakah Anda mengindikasikan bahwa hal itu dimungkinkan dengan OUTPUTklausa? Itu bukan karena itu semua adalah satu pernyataan. Juga hindari masalah keharusan membaca baris dua kali (dan mungkin kehilangan baris yang ditambahkan antara baca untuk sisipan dan baca untuk penghapusan)
Martin Smith
Ya, itulah yang saya maksudkan. Terima kasih, saya mengerti maksud Anda.
Dina
FWIW - metode ini akan menyebabkan pertumbuhan logfile mendekati ukuran tabel asli. Pastikan Anda bisa hidup dengan itu. Jika tidak bisa, pisahkan menjadi batch dengan DELETE TOP (N) dan loop While yang memeriksa variabel @@ rowcount.
Wjdavis5
1

Cara saya berpikir tentang melakukan pengarsipan (yang saya yakin juga tidak sempurna), adalah menambahkan kolom sedikit ke tabel arsip baru seperti 'Diarsipkan' yang akan memiliki nilai 1 setelah transfer rekaman berhasil. Dan setelah Anda mentransfer semua catatan, Anda dapat melakukan operasi penghapusan sambil juga mencari nilai bidang 'Diarsipkan' dari '1' yaitu Benar dari tabel yang diarsipkan.

Dan saya setuju dengan Mike untuk menggunakan Try / Catch.

avakharia
sumber
1

Coba ini:

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;
Nadeem
sumber