How can I run a raw sql query and get an ActiveRecord_Relation
instance returned?
On a sqlite3 db and Rails 4.2, ActiveRecords::Base.exec_query(sql)
returns an ActiveRecord_Result
instance. ActiveRecords::Base.execute(sql)
returns an array. This is troublesome because I cannot run subsequent "ActiveRecord queries" or raw sql queries on the returned objects.
More generally, I would like to know how to chain "complex" sql queries in Rails. By complex I mean I could not figure out a way to do it through the "ORM methods" given by ActiveRecords. And by chaining I mean I would like to break it down in several SQL queries, for performance reasons. Example: I just want to run the big heavy first SQL query once, store the result and then run lighter sql queries depending on the user behavior.
I am currently trying to optimize a database visualization through dataTables implemented with server-side-processing. The server has to run an unnecessarily complex SQL query every time the user interacts with the table because I could not break it down in simpler queries. I looked at the following questions but could not figure out a satisfying solution:
Rails raw SQL example
Convert Array#select to active record query in rails 4
Hash/Array to Active Record
Use the DbSet. SqlQuery() method to write raw SQL queries which return entity instances.
FromSql() method to execute raw SQL queries for the underlying database and get the results as entity objects.
Arel is a powerful SQL AST manager that lets us appropriately combine selection statements for simple to very complicated queries. However, reader be cautioned – Arel is still a private API provided by Rails. Meaning that future versions of Rails could be subject to changes in Arel.
This is a way to get an ActiveRecord_Relation from raw_sql.
It works best if you actually have a model matching the fields you're trying to retrieve, but as you can see with test_attribute, any data will be loaded.
# Just an example query, any query should be ok
query = <<-SQL
SELECT *, TRUE AS test_attribute
FROM users
WHERE sign_in_count < 10
SQL
relation = User.select('*').from("(#{query}) AS users")
relation.class
# User::ActiveRecord_Relation
relation.first.test_attribute
# true
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With