Sqlserver
 sql >> Teknologi Basis Data >  >> RDS >> Sqlserver

Menggunakan kondisi if dalam menyisipkan SQL Server

Polanya adalah (tanpa penanganan kesalahan):

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;

Anda tidak perlu membaca tabel #temp tambahan di sini. Anda sudah melakukannya dengan mencoba pembaruan. Untuk melindungi dari kondisi balapan, Anda melakukan hal yang sama seperti Anda melindungi blok apa pun dari dua atau lebih pernyataan yang ingin Anda isolasi:Anda akan membungkusnya dalam transaksi dengan tingkat isolasi yang sesuai (mungkin dapat serial di sini, meskipun itu semua hanya masuk akal ketika kita tidak berbicara tentang tabel #temp, karena itu menurut definisi serial).

Anda tidak lebih maju dengan menambahkan IF EXISTS check (dan Anda perlu menambahkan petunjuk penguncian untuk membuatnya aman/dapat diserialisasi), tetapi Anda dapat tertinggal lebih jauh, tergantung pada berapa kali Anda memperbarui baris yang ada vs. menyisipkan yang baru. Itu bisa menambahkan banyak I/O ekstra.

Orang mungkin akan meminta Anda untuk menggunakan MERGE (yang sebenarnya adalah beberapa operasi di belakang layar, dan juga perlu dilindungi dengan serializable), saya mendorong Anda untuk tidak melakukannya. Saya jelaskan alasannya di sini:

  • Berhati-hatilah dengan Pernyataan MERGE SQL Server

Untuk pola multi-baris (seperti TVP), saya akan menangani ini dengan cara yang hampir sama, tetapi tidak ada cara praktis untuk menghindari pembacaan kedua seperti yang Anda bisa dengan kasus satu baris. Dan tidak, MERGE tidak menghindarinya juga.

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;

Yah, saya kira ada cara untuk melakukannya, tetapi saya belum mengujinya secara menyeluruh:

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;

Dalam kedua kasus, Anda melakukan pembaruan terlebih dahulu, jika tidak, Anda akan memperbarui semua baris yang baru saja Anda sisipkan, yang akan sia-sia.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Buat Profil Email Database (SSMS)

  2. Sumber daya apa yang tersedia untuk penyetelan kinerja Database?

  3. Pernyataan BERGABUNG Bersyarat SQL Server

  4. Cara menggunakan Operator Logika EXISTS di SQL Server - Tutorial SQL Server / TSQL Bagian 125

  5. Kesalahan overflow aritmatika mengonversi ekspresi ke tipe data datetime. (sambil menampilkan tanggal waktu..)