Sqlserver
 sql >> Cơ Sở Dữ Liệu >  >> RDS >> Sqlserver

Làm thế nào để triển khai một thủ tục được lưu trữ Upsert có điều kiện?

Tôi tập hợp lại đoạn script sau để chứng minh thủ thuật này mà tôi đã sử dụng trong nhiều năm trước. Nếu bạn sử dụng nó, bạn sẽ cần phải sửa đổi nó cho phù hợp với mục đích của mình. Nhận xét theo sau:

/*
CREATE TABLE Item
 (
   Title      varchar(255)  not null
  ,Teaser     varchar(255)  not null
  ,ContentId  varchar(30)  not null
  ,RowLocked  bit  not null
)


UPDATE item
 set RowLocked = 1
 where ContentId = 'Test01'

*/


DECLARE
  @Check varchar(30)
 ,@pContentID varchar(30)
 ,@pTitle varchar(255)
 ,@pTeaser varchar(255)

set @pContentID = 'Test01'
set @pTitle     = 'TestingTitle'
set @pTeaser    = 'TestingTeasier'

set @check = null

UPDATE dbo.Item
 set
   @Check = ContentId
  ,Title  = @pTitle
  ,Teaser = @pTeaser
 where ContentID = @pContentID
  and RowLocked = 0

print isnull(@check, '<check is null>')

IF @Check is null
    INSERT dbo.Item (ContentID, Title, Teaser, RowLocked)
     values (@pContentID, @pTitle, @pTeaser, 0)

select * from Item

Mẹo ở đây là bạn có thể đặt giá trị trong các biến cục bộ trong câu lệnh Cập nhật. Ở trên, giá trị "cờ" chỉ được đặt nếu bản cập nhật hoạt động (nghĩa là, các tiêu chí cập nhật được đáp ứng); nếu không, nó sẽ không bị thay đổi (ở đây, bên trái là null), bạn có thể kiểm tra điều đó và xử lý cho phù hợp.

Đối với giao dịch và làm cho nó có thể tuần tự hóa, tôi muốn biết thêm về những gì phải được gói gọn trong giao dịch trước khi đề xuất cách tiếp tục.

- Addenda, theo dõi từ bình luận thứ hai bên dưới -----------

Ý tưởng của ông Saffron là một cách triệt để và chắc chắn để thực hiện quy trình này vì các khóa chính của bạn được xác định bên ngoài và được chuyển vào cơ sở dữ liệu (tức là bạn không sử dụng các cột nhận dạng - tôi thấy tốt, chúng thường bị sử dụng quá mức).

Tôi đã thực hiện thêm một số thử nghiệm (đã thêm ràng buộc khóa chính trên cột ContentId, bọc UPDATE và INSERT trong một giao dịch, thêm gợi ý có thể tuần tự hóa vào bản cập nhật) và vâng, điều đó sẽ làm được mọi thứ bạn muốn. Cập nhật không thành công sẽ khóa phạm vi trên phần đó của chỉ mục và điều đó sẽ chặn bất kỳ nỗ lực đồng thời nào để chèn giá trị mới đó vào cột. Tất nhiên, nếu N yêu cầu được gửi đồng thời, "đầu tiên" sẽ tạo ra hàng và nó sẽ được cập nhật ngay lập tức vào thứ hai, thứ ba, v.v. - trừ khi bạn đặt "khóa" ở đâu đó dọc theo dòng. Mẹo hay!

(Lưu ý rằng nếu không có chỉ mục trên cột khóa, bạn sẽ khóa toàn bộ bảng. Ngoài ra, khóa phạm vi có thể khóa các hàng ở "một trong hai bên" của giá trị mới - hoặc có thể chúng không, tôi đã không hãy kiểm tra cái đó. Không thành vấn đề, vì thời lượng của hoạt động phải [?] tính bằng mili giây một chữ số.)



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Thống kê gia tăng SQL Server 2014

  2. Chế độ xem tìm kiếm SQL Server 2005 cho các đối tượng cơ sở dữ liệu nhất định

  3. Lỗi khi chuyển đổi kiểu dữ liệu varchar

  4. SQL:Like vs Contains - Kết quả khác nhau

  5. Những điều bạn nên biết với NOCHECK khi kích hoạt ràng buộc CHECK trong SQL Server