web-dev-qa-db-ja.com

同じ行を更新するとマージが失敗する

MERGEステートメントが同じ行を複数回UPDATEまたはDELETEしようとしました。これは、ターゲット行が複数のソース行と一致する場合に発生します。 MERGEステートメントは、ターゲットテーブルの同じ行を複数回UPDATE/DELETEすることはできません。 ON句を調整して、ターゲット行が最大で1つのソース行と一致するようにするか、GROUP BY句を使用してソース行をグループ化します。

このエラーはupdateを使用して修正でき、ステートメントが存在しないことを知っています。

しかし、マージは2つのステートメントよりも高速になるため、マージでこれを実行する必要があります。

ソース:

+-----------+-----------+-------------------+---------+---------+----------+----------+
| Productid | Imagetype |     Imagename     | Website | Thumb90 | Thumb200 | Thumb500 |
+-----------+-----------+-------------------+---------+---------+----------+----------+
|   3144000 | small     | 3144000_small.jpg | Google  |       1 |        0 |        0 |
|   3144005 | medium    | 3144005_medium.jpg| Google  |       1 |        0 |        0 |
|   3144005 | medium    | 3144005_medium.jpg| Google  |       0 |        1 |        0 |
|   3144005 | medium    | 3144005_medium.jpg| Google  |       0 |        0 |        1 |
+-----------+-----------+-------------------+---------+---------+----------+----------+

ターゲット:

+-----------+-----------+-------------------+---------+---------+----------+----------+
| Productid | Imagetype |     Imagename     | Website | Thumb90 | Thumb200 | Thumb500 |
+-----------+-----------+-------------------+---------+---------+----------+----------+
|   3144000 | small     | 3144000_small.jpg | Google  |       0 |        0 |        0 |
|   3144000 | medium    | 3144000_medium.jpg| Google  |       1 |        0 |        0 |
|   3144000 | large     | 3144000_large.jpg | Google  |       1 |        0 |        0 |
|   3144005 | small     | 3144005_small.jpg | Google  |       0 |        1 |        0 |
|   3144005 | medium    | 3144005_medium.jpg| Google  |       0 |        0 |        0 |
|   3144005 | large     | 3144005_large.jpg | Google  |       0 |        0 |        1 |
+-----------+-----------+-------------------+---------+---------+----------+----------+

マージ:

+-----------+-----------+-------------------+---------+---------+----------+----------+
| Productid | Imagetype |     Imagename     | Website | Thumb90 | Thumb200 | Thumb500 |
+-----------+-----------+-------------------+---------+---------+----------+----------+
|   3144000 | small     | 3144000_small.jpg | Google  |       1 |        0 |        0 |
|   3144000 | medium    | 3144000_medium.jpg| Google  |       1 |        0 |        0 |
|   3144000 | large     | 3144000_large.jpg | Google  |       1 |        0 |        0 |
|   3144005 | small     | 3144005_small.jpg | Google  |       0 |        1 |        0 |
|   3144005 | medium    | 3144005_medium.jpg| Google  |       1 |        1 |        1 |
|   3144005 | large     | 3144005_large.jpg | Google  |       0 |        0 |        1 |
+-----------+-----------+-------------------+---------+---------+----------+----------+

クエリ:

MERGE INTO [luannw2016].[ImageThumbnailTrack] AS TARGET
USING #ImageThumbnailTrack AS SOURCE ON TARGET.ProductId = SOURCE.ProductId
AND TARGET.ImageType = SOURCE.ImageType
WHEN MATCHED
THEN
    UPDATE
    SET ImageName  = SOURCE.ImageName,
        Website    = SOURCE.Website,
        Thumb90    = SOURCE.Thumb90,
        Thumb200   = SOURCE.Thumb200,
        Thumb500   = SOURCE.Thumb500
WHEN NOT MATCHED
THEN
    INSERT ([ProductId],[ImageType],ImageName,Website,Thumb90,Thumb200,Thumb500)
    VALUES ([ProductId],[ImageType],ImageName,Website,Thumb90,Thumb200,Thumb500);
3
Ragul

私が 正当な理由でMERGEのファンではない であることは秘密ではありません。通常、MERGEを使用して顧客コードを表示するときは、個別のステートメントの「古い」方法(および他の人に勧める 同じことをする 、特にMERGEの専門家でない場合)。

マージは2つのステートメントよりも高速になるためです。

NO IT WO N'T。MERGEは、個別のステートメントとまったく同じセマンティクスを実行します。 まったくパフォーマンス上の利点はありません です。 それを読んでください とそれがどのように機能するかを理解していることを確認してください-自信がある場合はMERGEの方が速く、ステートメントが機能するようになったら、いくつかのテストを実行して証明してくださいそれ。結果に失望するでしょうが、少なくとも今は結論は事実に基づいています。

エラーメッセージはかなり明確だと思います。 ProductIdImageTypeは一意ではないため、ThumbXX列を比較に追加する必要がある場合があります。

_AND TARGET.Thumb90    = SOURCE.Thumb90
AND TARGET.Thumb200   = SOURCE.Thumb200
AND TARGET.Thumb500   = SOURCE.Thumb500
_

また、VALUES()リストを適切にエイリアスする必要があります。

_WHEN NOT MATCHED
THEN
    INSERT ([ProductId],[ImageType],...)
    VALUES (SOURCE.[ProductId],SOURCE.[ImageType],...);
_

私はこれを_UPDATE ... WHERE EXISTS_として書き、次に_INSERT ... WHERE NOT EXISTS_として書きます(もちろん、現在のMERGEステートメントには必要だが欠けている適切なトランザクションにラップされます)。

3
Aaron Bertrand