72

次の名前のデータを含むテーブルがありますenergydata

たった3列です

(webmeterID, DateTime, kWh)

テーブルに更新されたデータの新しいセットがありますtemp_energydata

DateTimeとはwebmeterID同じままです。ただし、kWh値はテーブルから更新する必要がありtemp_energydataます。

このためのT-SQLを正しい方法で作成するにはどうすればよいですか?

4

6 に答える 6

140

実際のSQLServerステートメントが必要であると仮定しますMERGE

MERGE INTO dbo.energydata WITH (HOLDLOCK) AS target
USING dbo.temp_energydata AS source
    ON target.webmeterID = source.webmeterID
    AND target.DateTime = source.DateTime
WHEN MATCHED THEN 
    UPDATE SET target.kWh = source.kWh
WHEN NOT MATCHED BY TARGET THEN
    INSERT (webmeterID, DateTime, kWh)
    VALUES (source.webmeterID, source.DateTime, source.kWh);

ソースにないターゲットのレコードも削除する場合:

MERGE INTO dbo.energydata WITH (HOLDLOCK) AS target
USING dbo.temp_energydata AS source
    ON target.webmeterID = source.webmeterID
    AND target.DateTime = source.DateTime
WHEN MATCHED THEN 
    UPDATE SET target.kWh = source.kWh
WHEN NOT MATCHED BY TARGET THEN
    INSERT (webmeterID, DateTime, kWh)
    VALUES (source.webmeterID, source.DateTime, source.kWh)
WHEN NOT MATCHED BY SOURCE THEN
    DELETE;

これはもう少し人気が出てきたので、注意すべきいくつかの注意点を付けて、この回答を少し拡張する必要があると思います。

まず、古いバージョンのSQLServerのステートメントの同時実行性の問題MERGEを報告するブログがいくつかあります。この問題が後の版で対処されたことがあるかどうかはわかりません。いずれにせよ、これは主にHOLDLOCKまたはSERIALIZABLEロックヒントを指定することで回避できます。

MERGE INTO dbo.energydata WITH (HOLDLOCK) AS target
[...]

より制限的なトランザクション分離レベルでも同じことを実現できます。

には、他にもいくつかの既知の問題がありMERGEます。(MicrosoftはConnectを無効にし、古いシステムの問題を新しいシステムの問題にリンクしなかったため、これらの古い問題を追跡するのは困難です。ありがとう、Microsoft!)私が知る限り、それらのほとんどは一般的ではありません。問題があるか、上記と同じロックのヒントで回避できますが、私はそれらをテストしていません。

現状では、私自身はステートメントに問題はありませんでしたが、今MERGEは常にWITH (HOLDLOCK)ヒントを使用しており、最も単純な場合にのみステートメントを使用することを好みます。

于 2013-02-11T06:25:55.350 に答える
14

構文を覚えられないので、私はよくベーコンビットの素晴らしい答えを使いました。

ただし、通常、CTEを追加として追加して、DELETE部分をより便利にします。これは、ターゲットテーブルの一部にのみマージを適用することが非常に多いためです。

WITH target as (
    SELECT * FROM dbo.energydate WHERE DateTime > GETDATE()
)
MERGE INTO target WITH (HOLDLOCK)
USING dbo.temp_energydata AS source
    ON target.webmeterID = source.webmeterID
    AND target.DateTime = source.DateTime
WHEN MATCHED THEN 
    UPDATE SET target.kWh = source.kWh
WHEN NOT MATCHED BY TARGET THEN
    INSERT (webmeterID, DateTime, kWh)
    VALUES (source.webmeterID, source.DateTime, source.kWh)
WHEN NOT MATCHED BY SOURCE THEN
    DELETE
于 2016-09-05T21:02:38.990 に答える
7

energydataのデータに基づいてレコードを更新する必要がある場合は、新しいレコードが含まれていないtemp_energydataと想定して、次のことを試してください。temp_enerydata

UPDATE e SET e.kWh = t.kWh
  FROM energydata e INNER JOIN 
       temp_energydata t ON e.webmeterID = t.webmeterID AND 
                            e.DateTime = t.DateTime

これがsqlfiddleの動作です

ただし、temp_energydata新しいレコードが含まれていて、できればenergydata1つのステートメントで挿入する必要がある場合は、BaconBitsの回答を使用する必要があります。

于 2013-02-11T06:11:16.037 に答える
0
UPDATE ed
SET ed.kWh = ted.kWh
FROM energydata ed
INNER JOIN temp_energydata ted ON ted.webmeterID = ed.webmeterID
于 2013-02-11T06:11:38.450 に答える
0
Update energydata set energydata.kWh = temp.kWh 
where energydata.webmeterID = (select webmeterID from temp_energydata as temp) 
于 2013-02-11T06:16:37.373 に答える
-7

正しい方法は次のとおりです。

UPDATE test1
INNER JOIN test2 ON (test1.id = test2.id)
SET test1.data = test2.data
于 2014-05-05T09:12:20.683 に答える