人力検索はてな
モバイル版を表示しています。PC版はこちら
i-mobile

http://q.hatena.ne.jp/1441975146

上記の続きです。
データベースの中のみでの重複チェックは調べてわかったのですが、登録したいデータがデータベースに重複していないか、そこで重複していないデータを登録する、という手順まではわかりませんでしたので、質問したいと思います。
外部データをデータベースに登録する際に、、どうしようかというのがわかりませんでした。

できれば、このRuby構文をこのままどうすればいいか教えて頂ければ助かります。
Sqlite3への登録部分ではありますが、小さな思い込みから行き止まりになることが多々あったので、、
よろしくお願いします。。


●質問者: FREEz
●カテゴリ:ウェブ制作
○ 状態 :終了
└ 回答数 : 1/1件

▽最新の回答へ

1 ● a-kuma3
●1500ポイント ベストアンサー

SQLite には INSERT OR REPLACE というのがあります。
これを使うと、プライマリキーが重複するレコードがあると上書きしてくれます。

def treat_data data

 ...

 // ★ ↓ ここ!
 sql = 'insert or replace into TEPCO(blackout_time, recover_time, pref, city, area, blackout_count, blackout_reason, update_time) values (?, ?, ?, ?, ?, ?, ?, ?);'
 db.execute(sql, [blackout_time, recover_time, pref, city, area, blackout_count, blackout_reason, update_time])

 ...

前回は手抜きして、通し番号の id なんてカラムを作ってプライマリキーにしましたが、もう必要ないですね。
id カラムを削除して、適当なキーをプライマリキーに指定してください。
例えば、発生時刻、都県、市町村あたりがプライマリキーでしょうか。

CREATE TABLE TEPCO (
 blackout_time text,
 recover_time text,
 pref text,
 city text,
 area text,
 blackout_count text,
 blackout_reason text,
 update_time text,
 PRIMARY KEY(blackout_time,pref,city)
);


停電情報が変わっていく様子も追っかけたい、というようなこともおっしゃってたので、用途に合わせてプライマリキーを決めてください。





追記です。

普通のというか、データがあるかどうかを判定して insert と update を切り替えて使うというベタな方法も書いておきます。

def treat_data data

 ...

 # プライマリキーで数を確認
 sql = 'select count(*) from TEPCO where blackout_time = ? and pref = ? and city = ?'
 rs = db.execute(sql, [blackout_time, pref, city])

 # データが無かったら insert
 if rs[0][0] == 0 then
 sql = 'insert into TEPCO(blackout_time, recover_time, pref, city, area, blackout_count, blackout_reason, update_time) values (?, ?, ?, ?, ?, ?, ?, ?);'
 db.execute(sql, [blackout_time, recover_time, pref, city, area, blackout_count, blackout_reason, update_time])
 # データがあったら update
 else
 sql = 'update TEPCO set blackout_time = ?, recover_time = ?, pref = ?, city = ?, area = ?, blackout_count = ?, blackout_reason = ?, update_time = ? where blackout_time = ? and pref = ? and city = ?'
 db.execute(sql, [blackout_time, recover_time, pref, city, area, blackout_count, blackout_reason, update_time, blackout_time, pref, city])
 end

ひとつのデータを書き込むのにふたつの SQL を出してたりするような性能面のこともありますが、ぱっと見てわかるように何よりも見づらい。
見づらさはメンテナンス性を悪くします。
多分、ちょいちょいいじるプログラムになるんだと思います。
保存する DB のレイアウトを変えたりしたくなることもあるかもしれない。
そういった辺りを考えると、シンプルなソースにしておくのが良いと思います。


FREEzさんのコメント
お早いお返事ありがとうございました。 思う以上に早くて驚いております。 まだ検証していませんが、まずはお礼まで。

a-kuma3さんのコメント
少し、追記しました。

FREEzさんのコメント
ありがとうございました、プログラムだけでなく動作させてみてかなり配慮されてるとよくわかり、 随分助かりました。 ちなみにIDは無駄に感じたようですが、あれかなり助かっていますよ?むしろこれ必要だったなと思ったほどです。 データの数がわかるし、順番を並び替えた時に元の基準なわけで、一見して見分けがつきますから。 特に逆順にした時に日付でもわかりますが、一目瞭然なのが助かります。 ifのrs[0][0] == 0の使い方が勉強になったので、これいいぁと使っています。 つまりはこれがプライマリキー。 insert or replace の方がシンプルでスタンダードだと思うのですが、、 これどちらも「原因」が変更された際に上書きされますよね。 if文の方はプライマリキーを変更しなくてもいけるのですが、insert or replaceの方はプライマリキーを変更しないとだめみたいですね。 基本がIDにあるので追記し重複してしまう、、データベースの設定さえしておけばプログラムの方が簡素な表現でいけるいい例だなと思いました。 どちらを使うにしても、IDカラムを消すのは惜しいw ありがとうございました。

FREEzさんのコメント
対象URLを追加していったら、一気に複数追加すると飛ばして対応してしまうことがありました。 ID残しておいてよかったです。一目瞭然に気付いたので。 URLをひとつずつ追加すると、問題なく追加されました、、ふたつ追加すると飛ばすこともありましたw 一度登録できないと飛ばしたところは再度動かしても追加されず、、注意しないといけないなぁ、、と。 あとは原因変わったら更新されるか、試したいけど変わらないと試せないから。。

FREEzさんのコメント
しばらく使ってみて気付いたのですが、 1日の結果として『停電履歴情報はありません。』の際に処理を飛ばすif文を入れた方がいいですね。 今のままだと 停電履歴情報はありません。 と書き込まれてしまうので、、 複数のURLで連続で処理しているとちゃんとなっているか不安でひとつずつチェックしていますが、原因が判明して書き換えられることがいまのところないので、判断できず、、
関連質問

●質問をもっと探す●



0.人力検索はてなトップ
8.このページを友達に紹介
9.このページの先頭へ
対応機種一覧
お問い合わせ
ヘルプ/お知らせ
ログイン
無料ユーザー登録
はてなトップ