2

テーブル tbl1(account, last_contact_date, insert_date) があります。プライマリ キーをアカウントと last_contact_date と定義しました。例えば

account    last_contact_date    insert_date
0001       09/01/2012           10/01/2012
0001       09/02/2012           10/02/2012

これで、別の一時テーブル #tmp(account, last_contact_date) からの新しいレコードができました。last_contact_date または insert_date に基づいて、条件付きで挿入します。(1) 挿入日が同じ日の場合、最大 last_contact_date でアカウントを更新します。

(0001, 09/01/2012, 10/02/2012) --no
(0001, 09/02/2012, 10/02/2012) --no
(0001, 09/03/2012, 10/02/2012) --update

(2) 挿入日が前日の場合、何もしない (これは決して起こらないことを私は知っている)

(0001, 09/01/2012, 10/01/2012) --no
(0001, 09/02/2012, 10/01/2012) --no
(0001, 09/03/2012, 10/01/2012) --no

(3)挿入日が翌日以降の場合、最大last_contact_dateで新規レコードを挿入します。

(0001, 09/01/2012, 10/03/2012) --no
(0001, 09/02/2012, 10/03/2012) --no
(0001, 09/03/2012, 10/03/2012) --insert

このクエリの書き方を手伝ってくれる人はいますか? 私は本当にアイデアが不足しています。

更新:カーソルを使用して上記のロジックを書くことになります。ありがとう。

4

1 に答える 1

0

このケースを処理するには、次のように IF が必要です (変数に現在のアカウントと insert_date があると仮定します。

-- First try to update
UPDATE tbl1 SET <whatever you need to update>
WHERE account = @account AND insert_date = @insert_date
    AND last_contact_date = 
        (SELECT MAX(last_contact_date) FROM tbl1
         WHERE account = @account AND insert_date = @insert_date)

-- Update failed because no matching record was found?
IF @@ROWCOUNT = 0
BEGIN
    INSERT <new record>
END

複数のプロセス/スレッドが同時にこれを行うと、どちらもレコードを見つけられず、両方が挿入しようとするため、主キー違反が発生する可能性があります。これを防ぐには、このコードを SERIALIZABLE トランザクションに入れるか、他の論理ロック メカニズムを使用する必要があります。

于 2012-10-04T19:48:44.650 に答える