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

Sử dụng điều kiện if trong SQL Server chèn

Mẫu là (không xử lý lỗi):

SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;

BEGIN TRANSACTION;

UPDATE #TProductSales SET StockQty = @StockQty, ETA1 = @ETA1
  WHERE ProductID = @ProductID;

IF @@ROWCOUNT = 0
BEGIN
  INSERT #TProductSales(ProductID, StockQTY, ETA1) 
    VALUES(@ProductID, @StockQTY, @ETA1);
END

COMMIT TRANSACTION;

Bạn không cần phải đọc thêm bảng #temp tại đây. Bạn đã làm điều đó bằng cách thử cập nhật. Để bảo vệ khỏi các điều kiện chủng tộc, bạn thực hiện giống như cách bạn bảo vệ bất kỳ khối nào gồm hai hoặc nhiều câu lệnh mà bạn muốn tách biệt:bạn bọc nó trong một giao dịch với mức cách ly thích hợp (có thể được tuần tự hóa ở đây, mặc dù tất cả chỉ có vậy có ý nghĩa khi chúng ta không nói về bảng #temp, vì đó là theo định nghĩa được tuần tự hóa).

Bạn không còn phải đi xa hơn nữa bằng cách thêm IF EXISTS kiểm tra (và bạn sẽ cần thêm các gợi ý khóa để làm cho nó an toàn / có thể tuần tự hóa), nhưng bạn có thể bị tụt lại xa hơn, tùy thuộc vào số lần bạn cập nhật các hàng hiện có so với chèn mới. Điều đó có thể làm tăng thêm rất nhiều I / O.

Mọi người có thể sẽ bảo bạn sử dụng MERGE (thực ra là nhiều thao tác đằng sau hậu trường, và cũng cần được bảo vệ bằng khả năng tuần tự hóa), tôi khuyên bạn không nên làm như vậy. Tôi giải thích tại sao ở đây:

  • Thận trọng với Câu lệnh MERGE của SQL Server

Đối với mẫu nhiều hàng (như TVP), tôi sẽ xử lý điều này theo cách tương tự, nhưng không có cách thực tế nào để tránh lần đọc thứ hai như bạn có thể làm với trường hợp một hàng. Và không, MERGE cũng không tránh nó.

SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;

BEGIN TRANSACTION;

UPDATE t SET t.col = tvp.col
  FROM dbo.TargetTable AS t
  INNER JOIN @TVP AS tvp
  ON t.ProductID = tvp.ProductID;

INSERT dbo.TargetTable(ProductID, othercols)
  SELECT ProductID, othercols
  FROM @TVP AS tvp
  WHERE NOT EXISTS
  (
    SELECT 1 FROM dbo.TargetTable
    WHERE ProductID = tvp.ProductID
  );

COMMIT TRANSACTION;

Chà, tôi đoán là có một cách để làm điều đó, nhưng tôi chưa kiểm tra kỹ điều này:

SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;

BEGIN TRANSACTION;

DECLARE @exist TABLE(ProductID int PRIMARY KEY);

UPDATE t SET t.col = tvp.col
  OUTPUT deleted.ProductID INTO @exist
  FROM dbo.TargetTable AS t
  INNER JOIN @tvp AS tvp
  ON t.ProductID = tvp.ProductID;

INSERT dbo.TargetTable(ProductID, othercols) 
  SELECT ProductID, othercols 
  FROM @tvp AS t 
  WHERE NOT EXISTS 
  (
    SELECT 1 FROM @exist 
    WHERE ProductID = t.ProductID
  );

COMMIT TRANSACTION;

Trong cả hai trường hợp, bạn thực hiện cập nhật trước, nếu không, bạn sẽ cập nhật tất cả các hàng bạn vừa chèn, điều này sẽ lãng phí.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Làm cách nào để tạo ràng buộc kiểm tra nhiều bảng?

  2. Sao chép bảng từ cơ sở dữ liệu này sang cơ sở dữ liệu khác trong SQL Server

  3. Kích thước tối đa cho một truy vấn SQL Server? Mệnh đề IN? Có một phương pháp tiếp cận tốt hơn không

  4. Cách sao chép cơ sở dữ liệu SQL Server từ phiên bản này sang phiên bản khác

  5. Kiểm tra / Thay đổi mức độ tương thích của cơ sở dữ liệu trong SQL Server (SSMS)