- PR -

DBへのUPDATEまたはINSERT処理に関して

投稿者投稿内容
ぬべたそ
ベテラン
会議室デビュー日: 2003/12/18
投稿数: 72
投稿日時: 2005-03-29 09:01
いつも参考にさせて頂いております。
早速ですが質問に移らせて頂きます。

データベースへのレコードのINSERT処理に際に、もし既存レコードが存在しPKの一意性制約に引っかかる場合はUPDATE処理を行いたい場合があると思います。
このような場合、どのような手順で処理するのが良いのでしょうか?
”ほとんど新規登録のレコード”という条件です。
以下思いついた2パターンを書いてみます。

【パターン1】
1.INSERTするレコードのPKをWHERE句に用い、SELECT処理を行う。
2.上記1で結果が0件の場合はINSERT処理を、1件の場合はUPDATE処理を行う。

【パターン2】
1.INSERT処理を行う。
2.上記1でSQLExceptionが発生した場合はUPDATE処理を行う。

どちらの方法が良いかや、他に良い方法があるなど、ご教授よろしくお願い致します。
かつのり
ぬし
会議室デビュー日: 2004/03/18
投稿数: 2015
お住まい・勤務地: 札幌
投稿日時: 2005-03-29 10:10
これが正解というのはないと思うのですが、私の場合

キーが重複した場合、すべてのカラムを上書きしても良いという条件なら
検査が面倒なのでマルチステートメントでdeleteしてinsertするようなSQLを書きます。

SQL実行を行う独自のAPIがあって、そのAPIがSQL実行でエラーが発生すると
ロールバックしたり無駄なログを吐くような仕様であれば、
重複検査を行いますし、もっと低レベルな実装であれば例外をキャッチして
updateを実行するという場合もあります。

SQL実行コストで考えれば、insertして例外でupdateするのが
一番コストがかからないかもしれないですね。

(株)ぽち
ぬし
会議室デビュー日: 2002/09/10
投稿数: 376
投稿日時: 2005-03-29 11:06
完全に好みの問題かとも思いますが

少なくともパターン2はどうかなぁ、と思います。
SQLExceptionは拾えますが、それが本当に一意性
のエラーで発生したものかどうかはわからないわけで。

私だったら普通に1ですかね。
未記入
ぬし
会議室デビュー日: 2004/09/17
投稿数: 667
投稿日時: 2005-03-29 12:40
引用:
検査が面倒なのでマルチステートメントでdeleteしてinsertするようなSQLを書きます。


この方法は楽なんだけど、外部参照制約違反になる可能性を考慮しないといけないですね。
かつのり
ぬし
会議室デビュー日: 2004/03/18
投稿数: 2015
お住まい・勤務地: 札幌
投稿日時: 2005-03-29 13:24
>未記入さん
なるほど。確かにそうですね。

議論の論点を変えて申し訳ないのですが、外部キーって設定していますか?

私の場合、ER図上では定義してもCREATE文からは外してしまいます。
理由としてはテストデータ作成やテーブル単位での
バックアップ・復元等のメンテが面倒だからという理由です。

しかし外部キーにはメリットが沢山ありますし、
最近では使うか使わないか悩んでいます・・・
未記入
ぬし
会議室デビュー日: 2004/09/17
投稿数: 667
投稿日時: 2005-03-29 15:17
引用:
議論の論点を変えて申し訳ないのですが、外部キーって設定していますか?


システムによって部分的に設定します。

引用:

理由としてはテストデータ作成やテーブル単位での
バックアップ・復元等のメンテが面倒だからという理由です。


同意。データベースと合わせて、入力画面を作成する場合は外部キーのメリットをそれほど享受できないので、開発時の利便性を優先して外部キーは設定しません。入力画面に表示する都合で必ず事前にマスタチェックを行いますので。

外部キーを設定するのは他システムとの連動部分などが多いですね。他システムで作成された CSV をロードするような仕組みの場合には、外部参照制約を設定したほうが検査コードを作る手間が省けて楽になることが多いです。

チェック制約も同様ですね。自アプリケーションで事前検査できる場合は設定しませんが、CSV ロードなどでは「この項目は 1, 2, 3 のいずれかの値しか設定できないように」とガチガチにチェック制約を付けます。
ぬべたそ
ベテラン
会議室デビュー日: 2003/12/18
投稿数: 72
投稿日時: 2005-03-29 16:54
みなさんご返信ありがとうございます。

今回は基本的にINSERT処理が大半を占めるということで、INSERTで失敗してからUPDATEしようかと思いましたが、SQLExceptionで一意性制約を調べなければならないのと、catch句中に処理を実装するのがなんとなく気持ち悪かったので質問させていただきました。

(株)ぽちさんの書かれたようにSELECTでチェックしてからINSERT/UPDATE処理しようと思います。

個人的な意見ですが外部参照は使っています。
ORACLEの場合、ON DELETE CASCADEで親レコードが削除されたタイミングで子レコードも削除するなどできるので、重宝しています。
未記入
ぬし
会議室デビュー日: 2004/09/17
投稿数: 667
投稿日時: 2005-03-29 17:32
引用:
ORACLEの場合、ON DELETE CASCADEで親レコードが削除されたタイミングで子レコードも削除するなどできるので、重宝しています。


連鎖削除って怖くて設定したことないんですけど・・・。そんなに便利ですか?
使わなくなった商品データをいくつか削除したら、大事な実績データがああああっっ!!
という場面がたやすく想像できちゃうんで、私は安全のために、連鎖削除は使わないようにしています。

スキルアップ/キャリアアップ(JOB@IT)