Di chuyển các hàng từ bảng này sang bảng khác


9

Tôi đang chuyển hồ sơ từ cơ sở dữ liệu này sang cơ sở dữ liệu khác, như là một phần của quá trình lưu trữ. Tôi muốn sao chép các hàng vào bảng đích và sau đó xóa các hàng tương tự khỏi bảng nguồn.

Câu hỏi của tôi là, cách hiệu quả nhất để kiểm tra xem lần chèn đầu tiên có thành công hay không trước khi xóa các hàng.

Ý tưởng của tôi là thế này, nhưng tôi cảm thấy có một cách tốt hơn:

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

Có tốt hơn / có thể kết hợp nó với chức năng RAISERROR không? Cảm ơn bạn!

Câu trả lời:


13

Tôi muốn giới thiệu cú pháp TRY / CATCH cùng với các giao dịch rõ ràng. Giả định của tôi cho giải pháp này là lý do cho lỗi chèn là một loại lỗi SQL có thể bị khóa (như vi phạm khóa, lỗi không khớp / lỗi chuyển đổi kiểu dữ liệu, v.v.). Cấu trúc sẽ trông như thế này:

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

Cách thức cấu trúc này hoạt động, nếu có bất kỳ lỗi nào xảy ra trong CHERTN hoặc XÓA, toàn bộ hành động sẽ được khôi phục. Điều này đảm bảo rằng toàn bộ hành động phải thành công để được hoàn thành. Nếu bạn cảm thấy điều đó là cần thiết, bạn có thể kết hợp nó với THWAY cho năm 2012 hoặc RAISERROR vào năm 2008 và trước đó để thêm logic bổ sung và buộc quay trở lại nếu logic đó không được đáp ứng.

Một tùy chọn khác là xem xét SET XACT_ABORT ON , mặc dù tôi cảm thấy rằng cú pháp TRY / CATCH mang lại cho bạn mức độ chi tiết cao hơn.


19

Nếu bảng lưu trữ của bạn không .

  • Đã kích hoạt kích hoạt được xác định trên nó.
  • Tham gia ở một trong hai bên của ràng buộc NGOẠI TỆ.
  • Có các ràng buộc KIỂM TRA hoặc quy tắc kích hoạt.

Bạn cũng có thể làm điều đó trong một statenent.

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

Điều này sẽ thành công hoặc thất bại với tư cách là một đơn vị và cũng tránh các điều kiện đua có thể xảy ra với các hàng được thêm vào giữa INSERTkho lưu trữ và DELETE(mặc dù WHEREđiều khoản của bạn có thể khiến điều này cực kỳ khó xảy ra).


Không có cái nào ở trên. Tôi cho rằng tôi có thể đi theo con đường đó, tôi thích sự tối giản mã. Tôi chỉ không muốn mất hồ sơ nếu chèn không thành công vì bất kỳ lý do. (ví dụ: khóa bảng, hết giờ, v.v.) Cảm ơn bạn!
Dina

@Dina - Bạn đã chỉ ra điều đó có thể với OUTPUTmệnh đề chưa? Không phải vì đó là tất cả một tuyên bố. Ngoài ra, tránh vấn đề phải đọc các hàng hai lần (và có thể mất các hàng được thêm vào giữa lần đọc để chèn và đọc để xóa)
Martin Smith

Vâng, đó là những gì tôi có ý nghĩa. Cảm ơn, tôi thấy quan điểm của bạn.
Dina

FWIW - phương pháp này sẽ gây ra sự tăng trưởng logfile gần bằng kích thước của bảng gốc. Hãy chắc chắn rằng bạn có thể sống với điều đó. Nếu bạn không thể, hãy chia nó thành các đợt với DELETE TOP (N) và vòng lặp While kiểm tra biến @@ rowcount.
Wjdavis5 17/03/2016

1

Cách tôi nghĩ về việc lưu trữ (mà tôi chắc chắn là không hoàn hảo), là thêm một cột bit vào bảng lưu trữ mới như 'Đã lưu trữ' sẽ có giá trị là 1 sau khi chuyển bản ghi thành công. Và một khi bạn chuyển tất cả các bản ghi, bạn có thể thực hiện thao tác xóa đồng thời tìm kiếm giá trị trường 'Lưu trữ' này là '1' tức là Đúng từ bảng lưu trữ.

Và tôi đồng ý với Mike về việc sử dụng Thử / Bắt.


1

Thử đi:

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;
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.