この記事では、SQLServerでUPDATEfromSELECTステートメントを使用するためのさまざまな方法について説明します。
データベースの世界では、静的データは通常保存されません。代わりに、既存のデータを更新したり、無関係なデータをアーカイブまたは削除したりするときに、変化し続けます。たとえば、ショッピングポータルの商品価格データを格納するテーブルがあるとします。顧客にさまざまな時期に製品割引を提供する可能性があるため、製品価格は常に変化します。この場合、商品レコードがすでに存在するため、テーブルに新しい行を追加することはできませんが、既存の商品の現在の価格を更新する必要があります。
ここで、UPDATEクエリが機能します。 UPDATEクエリは、データベースの既存の行のデータを変更します。 WHERE句を使用して、すべてのテーブル行を更新するか、更新の影響を受ける行を制限することができます。通常、SQLの更新は、直接参照する既存のテーブルに対して実行されます。たとえば、[employee]テーブルでは、要件により、すべてのアクティブな従業員の給与が10%増加する必要があります。この場合、直接参照SQLクエリは次のようになります。
従業員セット[salary]=salary +(salary * 10/100)を更新します。ここで[active] =1
従業員の場所を格納する別のテーブル[Address]があり、[Address]テーブルで使用可能なデータに基づいて[Employee]テーブルを更新する必要があるとします。 [従業員]テーブルのデータをどのように更新しますか?
幸いなことに、解決策があります–SELECTステートメントからのUPDATE。次のセクションでは、SELECTステートメントを使用して更新を実行するさまざまな方法について説明します。たとえば、[Employee]テーブルの列にはNULL値があります–次のスクリーンショットの[PostCode]と[City]。 [Address]テーブルには、[PostCode]列と[City]列の両方の値があります。
方法1:SELECTからの更新:結合方法
このメソッドは、SQL結合を使用して、更新が必要な値を含むセカンダリテーブルを参照します。したがって、ターゲットテーブルは、指定された条件の参照列データで更新されます。
この場合、UPDATEfromSELECTステートメントを使用するのは非常に簡単です。最初にSELECTステートメントを使用して、参照列とターゲット列の値をフェッチできます。
SELECT e.City,A.City, e.PostCode,A.PostCode FROM Employee e INNER JOIN [Address] a ON e.EmpID = A.EmpID
次に、クエリにわずかな変更を加え、以下に示すようにUPDATEステートメントを準備します。
- selectキーワードをupdateに置き換えます。
- 更新する必要のあるテーブル名またはエイリアス名を指定します。
- 参照列とターゲット列の間でsetキーワードと等号(=)を使用します。
UPDATE e set e.City=A.City, e.PostCode=A.PostCode FROM Employee e INNER JOIN [Address] a ON e.EmpID = A.EmpID
次に、UPDATEステートメントを実行し、ソース列とターゲット列の値が同じであることを確認します。
方法2:SELECTからの更新:MERGEステートメント
MERGEステートメントは、一致した行と一致しない行の両方のソーステーブルデータに基づいてターゲットテーブルのデータを操作する場合に役立ちます。これは、SELECTステートメント関数からUPDATEを実行するための代替方法です。
以下のMERGEステートメントの例では、次のタスクが実行されます。
- [Employee]テーブルのデータを更新するにはMERGEステートメントを使用します。
- 次に、USING句が適用されるときに別のテーブルを参照します。
- 次に、WHEN MATCHEDは、ソーステーブルとターゲットテーブル間のマージJOIN(内部結合)を指定します。
- 次に、THEN UPDATEステートメントとそれに続くソース列とターゲット列のマッピングを使用して、[PostCode]と[City]を[Address]テーブルから[Employee]テーブルに更新します。
- MERGEステートメントは常にセミコロン(;)で終わります。
MERGE Employee AS e USING(SELECT * FROM [Address]) AS A ON A.EmpID=e.EmpID WHEN MATCHED THEN UPDATE SET e.PostCode=A.PostCode , e.City = A.City;
メソッド3:SELECTからの更新:サブクエリメソッド
サブクエリは、SELECT、INSERT、UPDATE、およびDELETEステートメント内で使用できる内部クエリを定義します。他のテーブルから既存のテーブルデータを更新するのは簡単な方法です。
UPDATE Employee SET Employee.City=(SELECT [Address].city FROM [Address] WHERE [Address].EmpID = Employee.EmpId)
- 上記のクエリは、UPDATEステートメントのSET句でSELECTステートメントを使用します。
- サブクエリで一致する行が見つかった場合、更新クエリは特定の従業員のレコードを更新します。
- サブクエリがNULLを返す(一致する行がない)場合、それぞれの列のNULLを更新します。
- サブクエリが複数の一致する行を返す場合、UPDATEステートメントはエラーを発生させます–「SQLServerサブクエリは複数の値を返しました。サブクエリが比較演算子(=、!=、<、<=、>、> =)を使用する場合、これは許可されません。」
サブクエリの制限
- 比較演算子を使用したサブクエリには、INまたはEXISTS演算子に使用されている場合を除き、列名を1つだけ含めることができます。したがって、データの複数の列を更新する必要がある場合は、個別のSQLステートメントが必要です。
- ntextは使用できません 、テキスト 、および画像 サブクエリのデータ型。
- サブクエリに変更されていない比較演算子が含まれている場合、サブクエリにGROUPBY句とHAVING句を含めることはできません。変更されていない比較演算子は、キーワードANYまたはALLを使用できません。
SELECTステートメントからの異なるUPDATE間のパフォーマンス比較
このセクションでは、SELECTメソッドからのさまざまなUPDATE間のパフォーマンスを比較します。これを行うには、SQLクエリを一緒に実行し、SQL Server Management Studioで実際の実行プラン(Ctrl + M)を有効にして、Goステートメントを使用してそれらを分離することから始めます。
実行計画では、デモ用に次のデータを取得します。
- Join Methodのクエリコストは(バッチ全体に対して)41%です
- MERGEステートメントのクエリコストは34%です(バッチ全体と比較して)
- サブクエリメソッドのクエリコストは24%です(バッチ全体と比較して)
JOINメソッドは、個別の並べ替えに40%のコストを使用し、クラスター化されたインデックスの更新に35%のコストを使用します。
マージ結合は、ソースデータとターゲットデータの間でデータ行を照合するために内部結合を使用します。また、並べ替え演算子の相対コストも最大になります。
サブクエリは、列データを更新するための最速の方法です。強調表示されているように、クラスター化インデックスの更新とクラスター化インデックススキャンを使用します。
詳細については、以前の記事「SQL Server実行プラン—それとは何ですか。パフォーマンスの問題にどのように役立ちますか?」を参照してください。およびSQLServer実行プランを読み取って分析する方法。
概要
SELECTステートメントからUPDATEを実行するには、この記事で指定されている任意のメソッドを使用できます。サブクエリは効率的に機能しますが、前に強調したように、独自の制限があります。データベースの全体的なパフォーマンスは、テーブルデータ、更新の数、テーブルの関係、インデックス、統計によって異なります。