MAGAZINE

ルーターマガジン

Ruby

RubyからSQLiteのDBファイル(.sqlite3、.DB)を操作する

2019.10.25
Pocket

こんにちは。学生アルバイトの橋本です。突然ですが、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はお手軽かもしれません。

Pocket

CONTACT

お問い合わせ・ご依頼はこちらから