ywe*_*nbo 92 activerecord ruby-on-rails rawsql
我想执行一个更新原始sql,如下所示:
update table set f1=? where f2=? and f3=?
Run Code Online (Sandbox Code Playgroud)
这个SQL将由执行ActiveRecord::Base.connection.execute,但我不知道如何将动态参数值传递给方法.
有人可以给我任何帮助吗?
Bri*_*ing 97
它看起来不像Rails API公开方法来执行此操作.您可以尝试访问底层连接并使用它的方法,例如对于MySQL:
st = ActiveRecord::Base.connection.raw_connection.prepare("update table set f1=? where f2=? and f3=?")
st.execute(f1, f2, f3)
st.close
Run Code Online (Sandbox Code Playgroud)
我不确定是否还有其他后果(连接保持打开等).我将跟踪Rails代码以进行正常更新,以查看除了实际查询之外它正在做什么.
使用准备好的查询可以节省您在数据库中的少量时间,但除非您连续一百万次这样做,否则您可能最好只使用正常的Ruby替换来构建更新,例如
ActiveRecord::Base.connection.execute("update table set f1=#{ActiveRecord::Base.sanitize(f1)}")
Run Code Online (Sandbox Code Playgroud)
或者像评论者一样使用ActiveRecord说.
Pau*_*rth 30
ActiveRecord::Base.connection有一个quote方法,它接受一个字符串值(以及可选的列对象).所以你可以这样说:
ActiveRecord::Base.connection.execute(<<-EOQ)
UPDATE foo
SET bar = #{ActiveRecord::Base.connection.quote(baz)}
EOQ
Run Code Online (Sandbox Code Playgroud)
请注意,如果您使用的是Rails迁移或ActiveRecord对象,则可以将其缩短为:
connection.execute(<<-EOQ)
UPDATE foo
SET bar = #{connection.quote(baz)}
EOQ
Run Code Online (Sandbox Code Playgroud)
更新:正如@kolen指出的那样,你应该使用exec_update.这将为您处理报价并避免泄漏内存.签名的工作方式略有不同:
connection.exec_update(<<-EOQ, "SQL", [[nil, baz]])
UPDATE foo
SET bar = $1
EOQ
Run Code Online (Sandbox Code Playgroud)
这里的最后一个参数是一个表示绑定参数的元组数组.在每个元组中,第一个条目是列类型,第二个条目是值.您可以nil为列类型提供支持,但Rails通常会做正确的事情.
还有exec_query,exec_insert和exec_delete,这取决于你所需要的.
其他答案都没有向我展示如何使用命名参数,所以我最终结合exec_update了sanitize_sql:
User.connection.exec_update(
User.sanitize_sql(
[
"update users set name = :name where id = :id and name <> :name",
{
id: 123,
name: 'My Name'
}
]
)
)
Run Code Online (Sandbox Code Playgroud)
这在 Rails 5 上适用于我,它执行以下 SQL:
update users set name = 'My Name' where id = 123 and name <> 'My Name'
Run Code Online (Sandbox Code Playgroud)
User如果您没有,则需要使用现有的 Rails 模型。
?我想使用命名参数来避免使用or $1/$2等时出现排序问题。当我有多个参数时,位置排序有点令人沮丧,但命名参数允许我重构 SQL 命令,而无需更新参数。
你应该只使用类似的东西:
YourModel.update_all(
ActiveRecord::Base.send(:sanitize_sql_for_assignment, {:value => "'wow'"})
)
Run Code Online (Sandbox Code Playgroud)
这样就可以了。使用ActiveRecord::Base#send方法调用sanitize_sql_for_assignment会使 Ruby(至少是 1.8.7 版本)跳过sanitize_sql_for_assignment实际上是受保护方法的事实。
| 归档时间: |
|
| 查看次数: |
91721 次 |
| 最近记录: |