2010-11-23 7 views
2

私はRubyを学ぶために、Mr. Neighborly's Humble Little Ruby Bookを読んでいます。私の単純なRuby SQLite3のサンプルが失敗するのはなぜですか?

ほとんどの例は非常にわかりやすいので、私はRubyについてよく紹介していますが、DB関連の例を簡単に実行することはできません。

私はこのコードを実行しようとしている:(少し本で示された例から変更)

#!/usr/bin/ruby 
require 'rubygems' 
require 'dbi' 

DBI.connect('DBI:SQLite3:testdb', 'ruby', 'ruby') do | dbh | 
    dbh.do('CREATE TABLE slugs(name varchar(20), age int);') rescue puts "TABLE slugs already exists." 

    sql = "INSERT INTO slugs (name, age) VALUES (?, ?)" 

    dbh.prepare(sql) do |st| 
    1.upto(20) do |i| 
     st.execute("slug #{i}", "#{i}") 
    end 
    end 

end 

を実行すると、それはそれは私に次のエラーを与えて、データベース内の1行を挿入します。

 
/var/lib/gems/1.8/gems/sqlite3-ruby-1.3.2/lib/sqlite3/statement.rb:41:in `bind_param': library routine called out of sequence (SQLite3::MisuseException) 
    from /var/lib/gems/1.8/gems/sqlite3-ruby-1.3.2/lib/sqlite3/statement.rb:41:in `bind_params' 
    from /var/lib/gems/1.8/gems/sqlite3-ruby-1.3.2/lib/sqlite3/statement.rb:37:in `each' 
    from /var/lib/gems/1.8/gems/sqlite3-ruby-1.3.2/lib/sqlite3/statement.rb:37:in `bind_params' 
    from /var/lib/gems/1.8/gems/dbd-sqlite3-1.2.5/lib/dbd/sqlite3/statement.rb:71:in `bind_params' 
    from /var/lib/gems/1.8/gems/dbi-0.4.5/lib/dbi/handles/statement.rb:115:in `execute' 
    from /media/dev/ruby-prax/moi.rb:12 
    from /media/dev/ruby-prax/moi.rb:11:in `upto' 
    from /media/dev/ruby-prax/moi.rb:11 
    from /var/lib/gems/1.8/gems/dbi-0.4.5/lib/dbi/handles/database.rb:61:in `prepare' 
    from /media/dev/ruby-prax/moi.rb:10 
    from /var/lib/gems/1.8/gems/dbi-0.4.5/lib/dbi/handles/driver.rb:41:in `connect' 
    from /var/lib/gems/1.8/gems/dbi-0.4.5/lib/dbi.rb:148:in `connect' 
    from /media/dev/ruby-prax/moi.rb:5 
TABLE slugs already exists. 

私は現時点でUbuntu 10.04を使用しています。 バージョン情報:

 
[email protected]:/media/dev/ruby-prax$ ruby -v 
ruby 1.8.7 (2010-01-10 patchlevel 249) [x86_64-linux] 
[email protected]:/media/dev/ruby-prax$ gem list 

*** LOCAL GEMS *** 

abstract (1.0.0) 
daemons (1.1.0) 
dbd-mysql (0.4.4) 
dbd-odbc (0.2.5) 
dbd-sqlite3 (1.2.5) 
dbi (0.4.5) 
deprecated (3.0.0, 2.0.1) 
erubis (2.6.6) 
eventmachine (0.12.10) 
extlib (0.9.15) 
json_pure (1.4.6) 
mysql (2.8.1) 
rack (1.2.1) 
sqlite3-ruby (1.3.2) 
thin (1.2.7) 
thor (0.14.1) 
[email protected]:/media/dev/ruby-prax$ sqlite3 --version 
3.6.22 
[email protected]:/media/dev/ruby-prax$ 

私は間違っていますか?

slugs(name varchar(20), age int); 

いますが、挿入しようとしている:

答えて

1

あなたのテーブル定義は、整数ではありません

st.execute("slug #{i}", "#{i}") 

"#{i}"こと、それは文字列です。この例のようにiに変更してください。

st.execute("slug #{i}", i) 

次に何が起こるかを見てください。

+0

グッドピックアップ!しかし、それを変更した後、それは何の違いもありませんでした。私はまったく同じ動作を見ています。実際、sqlite3では、カラムをvarcharまたはintとして定義するかどうかにかかわらず、この単純な挿入に大きな違いはないようです。私はナメクジ(名前、年齢)を試しましたが、それでも同じエラーがありました。 –

+0

"name"に数値を渡そうとすると同じエラーが出ることが予想されます。これは型の不一致でもあります。名前は文字列でなければならず、年齢は整数/ fixnumでなければなりません。 –

+0

テスト中にデータベースを起動するときに表示される可能性のある別のエラーは、フィールドに「別個の」または「一意の」句があり、そのフィールドを一意の値のみに制限する場合です。シーケンシャルな値を挿入しようとするコードを再実行しようとすると、DBが狂って、実行する前にすべての行が強制的に削除されます。しかし、私はあなたが "別個の"句を持つフィールドを定義したとは思わない。 –

2

同じ問題が発生しました。準備されたINSERT文を複数回使用するとDBDが失敗するSQLiteドライバについては、issue on githubがあります。個人的には、そこでの回答でRDBIに移動しました。Ruby/DBIはもはや維持されていないようです。 RDBIに移行するには、コードの変更を最小限にする必要がありました。

+0

ありがとう、私はそれをチェックします。 –

0

私はRubyのsqlite3ライブラリのいくつかがステートメントクラスのリセットとクリアメソッドを欠いていると思っています。

同じSQL文を繰り返し実行すると、文が一度準備され、新しい値のセットで実行されます。しかし、ステートメントが実行され、再バインドされる前に、ステートメントをリセット(しばしばクリア)する必要があります。ポイントは、同じSQLを繰り返しコンパイルして最適化するよりも、使用したステートメントをリセットするほうが速いことです。あなたのほとんどは、おそらく、このすべてを知っている...しかし、ここに関連する部分のSQLiteのドキュメントへのリンクです:

https://www.sqlite.org/c3ref/stmt.html

私はリセットされ表示されていないとSQLite3の:: Statementクラスでの明確なメソッドなので、これらの何らかの形でこの実装から逃しているかもしれません、または再使用時に自動的にリセット/クリアする他のメカニズムがありますが、そのメカニズムは何らかの形で引き起こされません。しかし、それはドキュメントにも言及されていません...少なくとも私はそれを見つけることができませんでした。

私は、clear_bindingsとresetメソッドがSQLite3 :: Statementクラスにないと思います。

https://github.com/sparklemotion/sqlite3-ruby/issues/158

関連する問題