MAGAZINE
ルーターマガジン
RubyからSQLiteのDBファイル(.sqlite3、.DB)を操作する
こんにちは。学生アルバイトの橋本です。突然ですが、SQLiteというデータベースをご利用されたことはありますでしょうか? プログラミング入門者向けのWebアプリ作成チュートリアルや、ネイティブアプリ内の情報を一時的にキャッシュするための簡易的なDBとしての用途など、様々なところでSQLiteを目にしますね。
基本的には、弊社ではweb上のデータをクロールした際には、RubyのActiveRecordを用いてMySOLサーバーに接続してデータベースに格納していくことがほとんどで、ごくまれにSQLiteを扱う必要があったときに困った経験がありましたので、その経験を糧に、Rubyを使ってSQLiteを扱う方法についてご説明したいと思います。
RubyでのSQLite3の操作
RubyにはSQLite3を扱うライブラリが用意されているのでまずはインストール。
$ gem install sqlite3
最初に読み込みたいファイルを指定してDBのオブジェクトを作成します。今回は例として次の画像のようなデータが入ったmember.dbというDBを使います。
db = SQLite3::Database.new("member.db")そして、このDBからデータを取り出すのはexecuteメソッドを使って任意のSQLを実行するだけです。SELECT文を実行した時は該当レコードが配列で返って来るのでブロックに渡して処理を行うことができます。
db.execute("SELECT * FROM members WHERE gender == 'male'").each do |male| p male end =>出力 [1, "maeda", "male", 50] [2, "yamamoto", "male", 40] [3, "hashimoto", "male", 25] [4, "sakae", "male", 30] db.execute("SELECT name,gender FROM members WHERE age <= 30").each do |young| p young end =>出力 ["hashimoto", "male"] ["sakae", "male"] ["saito", "female"]少し使いずらいのは、レコードのそれぞれのカラムの値が配列になっていて、ActiveRecordでハッシュのようにkeyで値を取り出すことができないことでしょうか。
executeメソッドはSELECT以外のSQL文も実行できます。今回用いているDBも以下のように全てRubyから作成しました。
sql_create = <<SQL CREATE TABLE members ( id integer PRIMARY KEY AUTOINCREMENT, name text , gender text, age integer ); SQL members = [{'name'=>"maeda",'gender'=>"male",'age'=>50}, {'name'=>"yamamoto",'gender'=>"male",'age'=>40}, {'name'=>"hashimoto",'gender'=>"male",'age'=>25}, {'name'=>"sakae",'gender'=>"male",'age'=>30}, {'name'=>"saito",'gender'=>"female",'age'=>20} ] db.execute(sql_create) members.each do |member| sql_insert = "INSERT INTO members(name, gender, age) VALUES('#{member['name']}', '#{member['gender']}', '#{member['age']}')" db.execute(sql_insert) endデータの取り出しや編集が終わればDBを閉じてあげましょう。
db.closeまたSQLiteでは、ジャーナルファイル(ファイル名末尾に-wal,-shm,-journalが付随している)というものがあり、DBの変更を一時的にジャーナルファイルに保存して、DBを閉じる時に本体ファイルに反映します。この動作もtransactionメソッドやcommitメソッドで再現できます。スマホ端末内ではこのジャーナルファイルも一緒に存在していることが多いのですが、DBファイルをRubyで読み込む時に同じディレクトリにジャーナルファイルが置いてあれば勝手にジャーナルファイルの変更内容も読み込んでくれます。
2020/02/19追記
activerecordからもsqlite3のファイルへの接続が可能でした。activerecordを使えばfind_eachメソッドが使えるので、大きなデータを扱う時にメモリの消費を抑えられますね。ただし、モデル定義でprimary_keyを指定してあげないとfind_eachでエラーになるので注意が必要です。
require "active_record" # データベースへの接続 ActiveRecord::Base.establish_connection( adapter: 'sqlite3', database: 'member.db' ) class Member < ActiveRecord::Base self.primary_key = :id end Member.where(gender:'male').find_each do |member| p member end
おわりに
弊社ではクロールしたデータをMySQLとActiveRecordで操作して管理していますが、それでも、まれにSQLite方式のデータも扱うことがあります。色々な方式のファイルを自在に操れるようになりたいですね。また、ちょっとしたデータをDBファイルに保存しておきたいだけなら、接続設定やクラス定義が必要なActiveRecordよりもSQLite3はお手軽かもしれません。
CONTACT
お問い合わせ・ご依頼はこちらから