关于Rails中Postgresql的准备声明

时间:2012-12-10 17:05:14

标签: sql ruby-on-rails ruby-on-rails-3 postgresql prepared-statement

现在我正在从SQLite迁移到Postgresql,我遇到了这个问题。以下准备好的语句适用于SQLite:

id = 5
st = ActiveRecord::Base.connection.raw_connection.prepare("DELETE FROM my_table WHERE id = ?")
st.execute(id)
st.close

不幸的是它不能与Postgresql一起使用 - 它在第2行引发异常。 我一直在寻找解决方案并遇到了这个问题:

id = 5
require 'pg'
conn = PG::Connection.open(:dbname => 'my_db_development')
conn.prepare('statement1', 'DELETE FROM my_table WHERE id = $1')
conn.exec_prepared('statement1', [ id ])

这个在第3行失败。当我打印这样的异常时

rescue => ex

ex包含此

{"connection":{}}

在命令行中执行SQL有效。知道我做错了什么吗?

提前致谢!

1 个答案:

答案 0 :(得分:24)

如果您想使用prepare,那么您需要进行一些更改:

  1. PostgreSQL驱动程序希望看到编号占位符($1$2,...)不是问号,您需要为准备好的语句命名:

     ActiveRecord::Base.connection.raw_connection.prepare('some_name', "DELETE FROM my_table WHERE id = $1")
    
  2. 调用序列为prepare,后跟exec_prepared

    connection = ActiveRecord::Base.connection.raw_connection
    connection.prepare('some_name', "DELETE FROM my_table WHERE id = $1")
    st = connection.exec_prepared('some_name', [ id ])
    
  3. 上述方法适用于ActiveRecord和PostgreSQL,如果正确连接,PG::Connection.open版本应该可以正常工作。

    另一种方法是自己做引用:

    conn = ActiveRecord::Base.connection
    conn.execute(%Q{
        delete from my_table
        where id = #{conn.quote(id)}
    })
    

    这就是ActiveRecord通常在你背后做的事情。

    直接与数据库进行交互往往会对Rails造成一些混乱,因为Rails的人不认为你应该这样做。

    如果您真的只想删除没有干扰的行,可以使用delete

      

    删除()

         

    [...]

         

    只需在记录的主键上使用SQL DELETE语句删除该行,并且不会执行任何回调。

    所以你可以这样说:

    MyTable.delete(id)
    

    您将向数据库中发送一个简单的delete from my_tables where id = ...