QA@IT

RubyでSQLiteを使う時の変数の埋め込み方法は?

6100 PV

例えば、RubyからSQLiteの新規テーブルを作成したいときのテーブル名を変数にしたい場合どうすればいいのでしょうか?

db = SQLite3::Database.new("data.db")
sql = "create table {ここに変数をいれたい} (id int, title text)"
db.execute(sql)
db.close

データの追加を行う場合、プレースホルダとバインド値を使って以下のように書けることはわかったのですが、テーブル作成では書き方がわかりません。ご教授お願いします。

sql = "insert into test values (?, ?)"
db.execute(sql, 1, 'hoge')
db.execute(sql, 2, 'fuga')

回答

knsmr さんの回答の通り、自前で SQL を組み立てて execute に渡さないとだめそうです。ちょっと補足です。

execute でうまくいかないのは、execute がプリペアドステートメントを使っているためで、プリペアドステートメントには識別子 (テーブル名や列名など) はバインドできません。これは他の RDBMS でも同じです (たぶん)。

また、任意の文字列をテーブル名としてとるのなら、" で囲んで " をエスケープする必要があります。

require "sqlite3"

# 識別子のエスケープ
def quote_ident(string)
  escaped = string.gsub(/"/, '""')
  %("#{escaped}")
end

table_name = "table name has space and \""
db = SQLite3::Database.new("data.db")
sql = "create table #{quote_ident(table_name)} (id int, title text)"
db.execute(sql)

db.execute("select name from sqlite_master where type = 'table'")
# => [["table name has space and \""]]
編集 履歴 (0)
  • ご回答ありがとうございます。
    sql文で変数展開の書き方で書くと、セキュリティ的に微妙とかいう記事を見つけてたので、ほかの書き方を探してたのですが、しっかりエスケープ処理すれば大丈夫なんですかね。
    ありがとうございました!
    -

Rubyは文字列リテラルの中に変数を展開して挿入する「インターポレーション」ができるスクリプト言語の一派なので、それを使うと良いと思います。

name = "ken"
puts "Hello, #{name.capitalize}!"

=> Hello, Ken!

となるので、

require 'sqlite3'

db = SQLite3::Database.new("data.db")
table_name = "books"
sql = "CREATE TABLE #{table_name} (id int, title text)"
db.execute(sql)
db.close

とすればオッケーではないかと思います。Rubyのsqlite3のライブラリには、テーブル作成のための特別な記法やAPIは用意されていないようです。

同じことですが、クエリが長くなるようなら、

require 'sqlite3'

SQLite3::Database.new("data.db") do |db|
  table_name = "books"
  db.execute %Q{
  CREATE TABLE #{table_name} (
    id int,
    title text)
  }
end

としても良いかもしれません。%Qはダブルクオート同様に機能します。

編集 履歴 (0)
  • ご回答ありがとうございます!
    %Qで書くとヒアドキュメントみたいに書けるのですね。
    勉強になりました!ありがとうございした。
    -
ウォッチ

この質問への回答やコメントをメールでお知らせします。