sql >> データベース >  >> RDS >> Sqlserver

挿入SQLServerでif条件を使用する

    パターンは(エラー処理なしで):

    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;
    

    ここで#tempテーブルの追加の読み取りを実行する必要はありません。あなたはすでにアップデートを試すことによってそれをやっています。競合状態から保護するには、分離する2つ以上のステートメントのブロックを保護するのと同じことを行います。適切な分離レベルのトランザクションでラップします(ここではシリアル化できる可能性がありますが、すべてが#tempテーブルについて話しているのではない場合、それは定義上シリアル化されているため、意味があります。

    IF EXISTSを追加することで、これ以上先を行くことはできません。 チェックします(とにかく安全/シリアル化できるようにロックのヒントを追加する必要があります)が、既存の行を更新する回数と新しい行を挿入する回数によっては、さらに遅れる可能性があります。これにより、多くの余分なI/Oが発生する可能性があります。

    おそらく、MERGEを使用するように言われるでしょう。 (これは実際には舞台裏での複数の操作であり、シリアライズ可能で保護する必要もあります)、そうしないことをお勧めします。理由をここに示します:

    • SQLServerのMERGEステートメントには注意が必要です

    複数行のパターン(TVPなど)の場合、これはまったく同じ方法で処理しますが、単一行の場合のように2回目の読み取りを回避する実用的な方法はありません。いいえ、MERGE どちらも避けません。

    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;
    

    まあ、それを行う方法があると思いますが、私はこれを徹底的にテストしていません:

    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;
    

    いずれの場合も、最初に更新を実行します。そうしないと、挿入したばかりのすべての行が更新されるため、無駄になります。



    1. Dockerコンテナ上のPostgreSQLデータベースに接続します

    2. ドミノの秘密、またはドミノゲームデータモデル

    3. 以前のnull以外の値を効率的に選択するにはどうすればよいですか?

    4. JavaからOracle関数を呼び出す