Rails原始SQL示例

如何将此代码转换为原始sql并在rails中使用?因为当我在heroku中部署此代码时,有一个请求超时错误。我认为这将更快,如果我使用原始sql。

@payments = PaymentDetail.joins(:project).order('payment_details.created_at desc')
@payment_errors = PaymentError.joins(:project).order('payment_errors.created_at desc')


@all_payments = (@payments + @payment_errors)
341476 次浏览

您可以使用直接SQL对两个表进行单个查询。我将提供一个干净的查询示例,希望避免人们将变量直接放入字符串本身(SQL注入危险),即使这个示例没有指定它的需要:

@results = []
ActiveRecord::Base.connection.select_all(
ActiveRecord::Base.send(:sanitize_sql_array,
["... your SQL query goes here and ?, ?, ? are replaced...;", a, b, c])
).each do |record|
# instead of an array of hashes, you could put in a custom object with attributes
@results << {col_a_name: record["col_a_name"], col_b_name: record["col_b_name"], ...}
end

编辑:正如Huy所说,一个简单的方法是ActiveRecord::Base.connection.execute("...")。另一种方法是ActiveRecord::Base.connection.exec_query('...').rows。你可以使用原生的预处理语句,例如,如果使用postgres,预处理语句可以使用raw_connection、prepare和exec_prepared完成,如https://stackoverflow.com/a/13806512/178651中所述

你也可以把原始SQL片段放入ActiveRecord关系查询:http://guides.rubyonrails.org/active_record_querying.html 以及在关联、作用域等中。你可以用ActiveRecord关系查询构造相同的SQL,也可以用ARel做一些很酷的事情,就像Ernie在http://erniemiller.org/2010/03/28/advanced-activerecord-3-queries-with-arel/中提到的那样。当然,还有其他orm, gems等

如果这将被大量使用,并且添加索引不会导致其他性能/资源问题,那么可以考虑在DB中为payment_details添加一个索引。Created_at和for payment_errors.created_at。

如果有很多记录,而不是所有的记录需要一次显示,可以考虑使用分页:

如果需要分页,可以考虑先在DB中创建一个名为payment_records的视图,它将payment_details表和payment_errors表结合在一起,然后为该视图创建一个模型(该模型将是只读的)。一些db支持物化视图,这对于性能来说可能是个好主意。

还要考虑Rails服务器和DB服务器上的硬件或虚拟机规格、配置、磁盘空间、网络速度/延迟等。,邻近性等等。如果你没有,考虑把DB放在不同的服务器/VM上,而不是Rails应用,等等。

你可以这样做:

sql = "Select * from ... your sql query here"
records_array = ActiveRecord::Base.connection.execute(sql)

records_array将是你的sql查询在一个数组中的结果,你可以遍历这个数组。

我知道这很旧…但我今天遇到了同样的问题,我找到了一个解决办法:

Model.find_by_sql

如果你想实例化结果:

Client.find_by_sql("
SELECT * FROM clients
INNER JOIN orders ON clients.id = orders.client_id
ORDER BY clients.created_at desc
")
# => [<Client id: 1, first_name: "Lucas" >, <Client id: 2, first_name: "Jan">...]

Model.connection.select_all('sql').to_hash

如果你只想要一个值的哈希值:

Client.connection.select_all("SELECT first_name, created_at FROM clients
WHERE id = '1'").to_hash
# => [
{"first_name"=>"Rafael", "created_at"=>"2012-11-10 23:23:45.281189"},
{"first_name"=>"Eileen", "created_at"=>"2013-12-09 11:22:35.221282"}
]

结果对象:

select_all返回一个result对象。你可以用它来变魔术。

result = Post.connection.select_all('SELECT id, title, body FROM posts')
# Get the column names of the result:
result.columns
# => ["id", "title", "body"]


# Get the record values of the result:
result.rows
# => [[1, "title_1", "body_1"],
[2, "title_2", "body_2"],
...
]


# Get an array of hashes representing the result (column => value):
result.to_hash
# => [{"id" => 1, "title" => "title_1", "body" => "body_1"},
{"id" => 2, "title" => "title_2", "body" => "body_2"},
...
]


# ActiveRecord::Result also includes Enumerable.
result.each do |row|
puts row['title'] + " " + row['body']
end

来源:

  1. ActiveRecord -查找by 李SQL < / >。< / >
  2. Ruby on Rails -活动记录结果 李< / >。< / >

你可以使用ActiveRecord来执行原始查询。我建议使用SQL块

query = <<-SQL
SELECT *
FROM payment_details
INNER JOIN projects
ON projects.id = payment_details.project_id
ORDER BY payment_details.created_at DESC
SQL


result = ActiveRecord::Base.connection.execute(query)

你也可以混合原始SQL和ActiveRecord条件,例如,如果你想在条件中调用一个函数:

my_instances = MyModel.where.not(attribute_a: nil) \
.where('crc32(attribute_b) = ?', slot) \
.select(:id)

我想使用ActiveRecord类的exec_query,因为它返回查询转换为对象的映射,所以当主题是Raw SQL时,对对象进行迭代非常实用和高效。

例子:

values = ActiveRecord::Base.connection.exec_query("select * from clients")
p values

并返回这个完整的查询:

[{"id": 1, "name": "user 1"}, {"id": 2, "name": "user 2"}, {"id": 3, "name": "user 3"}]

只获取值的列表

p values.rows


[[1, "user 1"], [2, "user 2"], [3, "user 3"]]

只获取字段列

p values.columns


["id", "name"]