module ActiveRecord::Querying

def find_by_sql(sql, binds = [], preparable: nil, allow_retry: false, &block)

injection attacks (https://guides.rubyonrails.org/security.html#sql-injection).
Note that building your own SQL query string from user input may expose your application to

Post.find_by_sql ["SELECT body FROM comments WHERE author = :user_id OR approved_by = :user_id", { :user_id => user_id }]
Post.find_by_sql ["SELECT title FROM posts WHERE author = ? AND created > ?", author_id, start_date]

You can use the same string replacement techniques as you can with ActiveRecord::QueryMethods#where :

# => [#"Ruby Meetup", "author"=>"Quentin"}>, ...]
Post.find_by_sql "SELECT p.title, c.author FROM posts p, comments c WHERE p.id = c.post_id"
# A simple SQL query spanning multiple tables

change your call if you switch engines.
database-specific terms will lock you into using that particular database engine, or require you to
no database agnostic conversions performed. This should be a last resort because using
The +sql+ parameter is a full SQL query as a string. It will be called as is; there will be

table.
SELECT will be attributes of the model, whether or not they are columns of the corresponding
If you call a complicated SQL query which spans multiple tables, the columns specified by the

a +Product+ object with the attributes you specified in the SQL query.
this method from. For example, if you call Product.find_by_sql, then the results will be returned in
be returned as an array, with the requested columns encapsulated as attributes of the model you call
Executes a custom SQL query against your database and returns all the results. The results will
def find_by_sql(sql, binds = [], preparable: nil, allow_retry: false, &block)
  result = with_connection do |c|
    _query_by_sql(c, sql, binds, preparable: preparable, allow_retry: allow_retry)
  end
  _load_from_sql(result, &block)
end