web-dev-qa-db-ja.com

内部結合を使用したSQL Serverの更新

3つのテーブルがあります(簡略化):

 tblOrder(OrderId INT)  
  tblVariety(VarietyId INT,Stock INT)  
  tblOrderItem(OrderId,VarietyId,Quantity INT)

注文する場合、これを使用して在庫レベルをドロップします。

UPDATE tblVariety  
SET tblVariety.Stock = tblVariety.Stock - tblOrderItem.Quantity  
FROM tblVariety  
INNER JOIN tblOrderItem ON tblVariety.VarietyId = tblOrderItem.VarietyId  
INNER JOIN tblOrder ON tblOrderItem.OrderId = tblOrder.OrderId  
WHERE tblOrder.OrderId = 1

同じOrderIdに対して同じVarietyIdを持つtblOrderItemに2つの行が存在するまでは問題ありません。この場合、行の1つだけが在庫更新に使用されます。そこに何らかの形でGROUP BY VarietyIdを実行しているようです。

誰かが光を当てることはできますか?どうもありがとう。

25
Geoff

私の推測では、簡略化されたスキーマを示したため、特定のOrderIDに対してVarietyID値が繰り返される理由を特定する情報が欠落しています。

複数の行がある場合、SQL Serverは更新のためにそのうちの1つを任意に選択します。

この場合、最初にグループ化する必要があります

UPDATE V
SET
   Stock = Stock - foo.SumQuantity
FROM
    tblVariety V
    JOIN
    (SELECT SUM(Quantity) AS SumQuantity, VarietyID
     FROM tblOrderItem
      JOIN tblOrder ON tblOrderItem.OrderId = tblOrder.OrderId  
     WHERE tblOrder.OrderId = 1
     GROUP BY VarietyID
    ) foo ON V.VarietyId = foo.VarietyId  

そうでない場合、重複するOrderID/VarietyIDの組み合わせを許可する場合、OrderItemsテーブルのPKは間違っています(PKはOrderID/VarietyIDであるか、これらは一意に制約される必要があります)

43
gbn

ドキュメントから [〜#〜] update [〜#〜]

UPDATEステートメントの結果は、更新される各列オカレンスに対して1つの値のみが使用できるように指定されていないFROM句がステートメントに含まれている場合、未定義です(言い換えると、 UPDATEステートメントが決定的でない場合)たとえば、次のスクリプトでUPDATEステートメントを指定すると、テーブルsの両方の行がUPDATEステートメントのFROM句の条件を満たしますが、 sのどの行がテーブルtの行の更新に使用されるかは未定義です。

CREATE TABLE s (ColA INT, ColB DECIMAL(10,3))
GO
CREATE TABLE t (ColA INT PRIMARY KEY, ColB DECIMAL(10,3))
GO
INSERT INTO s VALUES(1, 10.0)
INSERT INTO s VALUES(1, 20.0)
INSERT INTO t VALUES(1, 0.0)
GO
UPDATE t 
SET t.ColB = t.ColB + s.ColB
FROM t INNER JOIN s ON (t.ColA = s.ColA)
GO
12
Adriaan Stander

更新を行っています。一度更新されます。

編集:解決するために、orderidとvarietyidで注文項目をグループ化するサブクエリを追加し、金額を合計することができます。

1