Rails原始SQL示例

Joh*_*ash 222 sql ruby-on-rails

如何将此代码转换为原始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)
Run Code Online (Sandbox Code Playgroud)

Huy*_*Huy 400

你可以这样做:

sql = "Select * from ... your sql query here"
records_array = ActiveRecord::Base.connection.execute(sql)
Run Code Online (Sandbox Code Playgroud)

records_array 然后是你可以迭代的数组中的SQL查询的结果.

  • 然后你需要在这个'PG :: Result`对象上调用`values`来获得结果数组 (53认同)
  • 旁注:`records_array`对于不同的数据库适配器将具有不同的类型.如果您正在使用PG,它将是`PG :: Result`的实例,而不是`Array`. (49认同)
  • 我更喜欢`ActiveRecord :: Base.connection.exec_query`,因为它返回一个`ActiveRecords :: Result`对象,它有一些方便的方法,如`.columns`和`.rows`来访问标题和值.来自`.execute`的哈希数组很难处理,当我使用SUM GROUP BY子句运行时,给了我多余的结果. (14认同)
  • 弃用警告:不推荐使用#connection,而是通过该类访问它. (4认同)
  • @ baash05你是什么意思"赞成通过课堂访问它." - 这里讨论了如何在没有模型的情况下访问该表 (3认同)

Joã*_*tta 162

我知道这已经过时了......但我今天遇到了同样的问题并找到了解决方案:

Model.find_by_sql
Run Code Online (Sandbox Code Playgroud)

如果要实例化结果:

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">...]
Run Code Online (Sandbox Code Playgroud)
Model.connection.select_all('sql').to_hash
Run Code Online (Sandbox Code Playgroud)

如果你只想要散列值:

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"}
]
Run Code Online (Sandbox Code Playgroud)

结果对象:

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
Run Code Online (Sandbox Code Playgroud)

资料来源:

  1. ActiveRecord - 由SQL查找.
  2. Ruby on Rails - 活动记录结果 .

  • `#find_by_sql`正是我想要的,非常感谢你. (6认同)

Gar*_*ver 25

您可以直接使用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
Run Code Online (Sandbox Code Playgroud)

编辑:正如Huy所说,一个简单的方法是ActiveRecord::Base.connection.execute("...").另一种方式是ActiveRecord::Base.connection.exec_query('...').rows.并且您可以使用本机预处理语句,例如,如果使用postgres,可以使用raw_connection,prepare和exec_prepared完成预准备语句,如/sf/answers/966455871/中所述

您还可以将原始SQL片段放入ActiveRecord关系查询:http://guides.rubyonrails.org/active_record_querying.html 以及关联,范围等.您可以使用ActiveRecord关系查询构建相同的SQL,并且可以使用ARel在http://erniemiller.org/2010/03/28/advanced-activerecord-3-queries-with-arel/中提到了ARel .而且,当然还有其他ORM,宝石等.

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

如果需要立即显示大量记录而非所有记录,请考虑使用分页:

如果您需要分页,请考虑在数据库中首先创建一个名为payment_records的视图,该视图将payment_details和payment_errors表组合在一起,然后为视图创建一个模型(该模型将是只读的).有些DB支持物化视图,这可能是性能的好主意.

还要考虑Rails服务器和数据库服务器上的硬件或VM规格,配置,磁盘空间,网络速度/延迟等,接近度等.如果你没有等,考虑把数据库放在不同的Rails应用程序的服务器/ VM上.


Dee*_*ale 25

您可以使用执行原始查询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)
Run Code Online (Sandbox Code Playgroud)

  • 虽然您可以这样做,但它可能会让您面临 SQL 注入的可能性 (5认同)

Dar*_*ich 9

我想工作,exec_query对中ActiveRecord类,因为它返回的查询转变为对象的映射,所以它会非常实用,富有成效的迭代与对象时,主题是原始的SQL。

例子:

values = ActiveRecord::Base.connection.exec_query("select * from clients")
p values
Run Code Online (Sandbox Code Playgroud)

并返回这个完整的查询:

[{"id": 1, "name": "user 1"}, {"id": 2, "name": "user 2"}, {"id": 3, "name": "user 3"}]
Run Code Online (Sandbox Code Playgroud)

仅获取值列表

p values.rows

[[1, "user 1"], [2, "user 2"], [3, "user 3"]]
Run Code Online (Sandbox Code Playgroud)

仅获取字段列

p values.columns

["id", "name"]
Run Code Online (Sandbox Code Playgroud)