Get results of SQL Query as string in Rails - sql

when i run a complicated sql query from the command line like this
sqlite3 db/development.sqlite3 < queries.sql
i get a result like this
Competency Name|Component Name|3.77|4.0|0.23
Another Competency Name|Another Component Name|3.77|4.0|0.23
which i can easily parse like this
hidden_strengh_strings = results.split("\n")[1..-1];
hidden_strengh_strings.each do |hidden_strength_string|
hidden_strengh_values = hidden_strength_string.split("|");
hidden_strength = {}
hidden_strength.merge!(:competency => hidden_strengh_values[0]);
hidden_strength.merge!(:component => hidden_strengh_values[1]);
hidden_strength.merge!(:reviewer_average_score => hidden_strengh_values[2]);
hidden_strength.merge!(:reviewee_average_score => hidden_strengh_values[3]);
hidden_strength.merge!(:exceedance => hidden_strengh_values[4]);
hidden_strengths << hidden_strength
end
but i have no idea how to get these results from within ActiveRecord.
results = ActiveRecord::Base.connection.execute(File.open(Rails.root.join('queries.sql'), 'r') { |f| f.read } );
doesn't seem to do what i want it to.
i'd be happy to take any approach to solve this problem. even rewriting the sql from within the ActiveRecord DSL. but i need help finding the right direction.
thanks : )

Nishant lead me to the solution.
ActiveRecord::Base.connection.execute
Works fine its just that the query started with:
select 'HIDDEN STRENGTHS';
so exec ended at the semicolon.
Thanks!

Related

How to order by an associated model in Rails 4, and specify a direction?

In Rails 3.2.17, i could have the following:
scope :sorted, -> { joins(:other).order({:other => :code}, :code) }
Which produces the following SQL:
SELECT [things].* FROM [things] INNER JOIN [others] ON [others].[id] = [things].[other_id] ORDER BY [others].[code] ASC, [things].[code] ASC
The same code in Rails 4.0.4 gives the following error, however:
Direction should be :asc or :desc
But, I cannot figure out a way to keep the ordering and specify the direct. The scope below, for example, gives the same error:
scope :sorted, -> { joins(:other).order({:other => {:code => :asc}}, :code => :asc) }
EDIT: To be clear, I want to use the Hash style syntax and do not want to write raw SQL strings
This looks like a bug in Rails 4.0+ (something about order accepting nested hashes)
I found a Github issue for you explaining the issue
They recommend using source:, but that's only for an association declaration. If you find the answer, I will gladly remove this, but hopefully it will help you!

Rails 3: convert session[:params] to correct activerecord query

I have two models, Foo and Bar, with same attributes, and I'm 'caching' user "search params" into a session variable, that ends into something like this:
session[:search_params] => {"price"=>"15.0", "air_conditioner"=>"0", "fireplace"=>"0", "number_of_rooms"=>"1", "balcony"=>"0"}
I'd like to search both Foo and Bar for entries that match this query.
For now, I'm doing:
#foo = Foo.new(session[:search_params])
search_attributes = #foo.attributes
search_attributes.delete 'id'
search_attributes.delete 'created_at'
search_attributes.delete 'updated_at'
#results = Foo.where(search_attributes)
#results += Bar.where(search_attributes)
that is REALLY UGLY.
Could anyone tell me a better/the correct way?
Thanks in advance.
EDIT
Also, some params in the session[:search_params] that are "0", are actually 'false' on the database (booleans) (filled by checkboxes), so I have to do some "conversion" into this fields so that the query is done correctly, i.e., getting for example air_conditioner => 'false' instead of air_conditioner => '0'.
I wouldn't follow that path if I were you. I would go with a solution like https://github.com/ernie/meta_search
You can use Dynamic Attribute-Based Finders: api.
So
#results = Foo.find_by_price_and_air_conditioner_and_fireplace_and_number_of_rooms_and_balcony(session[:search_params])
Also, you won't have to delete the extraneous information from session.

Optimize the query PostgreSql-8.4

I have rails controller coding as below:
#checked_contact_ids = #list.contacts.all(
:conditions => {
"contacts_lists.contact_id" => #list.contacts.map(&:id),
"contacts_lists.is_checked" => true
}
).map(&:id)
its equivalent to sql
SELECT *
FROM "contacts"
INNER JOIN "contacts_lists" ON "contacts".id = "contacts_lists".contact_id
WHERE ("contacts_lists".list_id = 67494 )
This above query takes more time to run, I want another way to run the same query with minimum time.
Is anyone knows please notice me Or is it possible? or is the above query enough for give output?
I am waiting information...................
I think the main problem with your original AR query is that it isn't doing any joins at all; you pull a bunch of objects out of the database via #list.contacts and then throw most of that work away to get just the IDs.
A first step would be to replace the "contacts_lists.contact_id" => #list.contacts.map(&:id) with a :joins => 'contact_lists' but you'd still be pulling a bunch of stuff out of the database, instantiating a bunch of objects, and then throwing it all away with the .map(&:id) to get just ID numbers.
You know SQL already so I'd probably go straight to SQL via a convenience method on your List model (or whatever #list is), something like this:
def checked_contact_ids
connection.execute(%Q{
SELECT contacts.id
FROM contacts
INNER JOIN contacts_lists ON contacts.id = contacts_lists.contact_id
WHERE contacts_lists.list_id = #{self.id}
AND contacts_lists.is_checked = 't'
}).map { |r| r['id'] }
end
And then, in your controller:
#checked_contact_ids = #list.checked_contact_ids
If that isn't fast enough then review your indexes on the contacts_lists table.
There's no good reason not go straight to SQL when you know exactly what data you need and you need it fast; just keep the SQL isolated inside your models and you shouldn't have any problems.

Associated models and SUM query in Rails

I've got two Rails models, a Child and a Parent say.
I know that I can do this:
Child.sum(:income, :conditions => "parent_id = #{#parent_id}")
But I want to be able to do this:
Parent.children.sum(:income)
But this is giving me the wrong values if I try it. Is there a more concise way of writing
Child.sum(:income, :conditions => "parent_id = #{#parent_id}")
?
TIA
[ps: Rails 3 dev environment]
Sorry but I have just found out the answer to this. I needed to add to_a to the collection of Child objects, and call a proc, as so:
Parent.children.to_a.sum(&:income)
This works a charm.
Sorry for bumping up an old thread, but I think I found better(best?) solution. Below is code for my project that I ended up
self.purchases.where(:script_id => script_id, :approved => true).sum(:instances)
It produces one query that does exactly what I need
SELECT SUM("purchases"."instances") AS sum_id FROM "purchases" WHERE "purchases"."customer_id" = 1 AND "purchases"."script_id" = 1 AND "purchases"."approved" = 't'
I ran into an issue where the child was delegating to the parent and I needed to find a sum.
children.to_a.sum(:parent_income)
was giving me a major N+1 problem. The solution was to use:
children.joins(:parent).sum(:income)

Encapsulating SQL in a named_scope

I was wondering if there was a way to use "find_by_sql" within a named_scope. I'd like to treat custom sql as named_scope so I can chain it to my existing named_scopes. It would also be good for optimizing a sql snippet I use frequently.
While you can put any SQL you like in the conditions of a named scope, if you then call find_by_sql then the 'scopes' get thrown away.
Given:
class Item
# Anything you can put in an sql WHERE you can put here
named_scope :mine, :conditions=>'user_id = 12345 and IS_A_NINJA() = 1'
end
This works (it just sticks the SQL string in there - if you have more than one they get joined with AND)
Item.mine.find :all
=> SELECT * FROM items WHERE ('user_id' = 887 and IS_A_NINJA() = 1)
However, this doesn't
Items.mine.find_by_sql 'select * from items limit 1'
=> select * from items limit 1
So the answer is "No". If you think about what has to happen behind the scenes then this makes a lot of sense. In order to build the SQL rails has to know how it fits together.
When you create normal queries, the select, joins, conditions, etc are all broken up into distinct pieces. Rails knows that it can add things to the conditions without affecting everything else (which is how with_scope and named_scope work).
With find_by_sql however, you just give rails a big string. It doesn't know what goes where, so it's not safe for it to go in and add the things it would need to add for the scopes to work.
This doesn't address exactly what you asked about, but you might investigate 'contruct_finder_sql'. It lets you can get the SQL of a named scope.
named_scope :mine, :conditions=>'user_id = 12345 and IS_A_NINJA() = 1'
named_scope :additional {
:condtions => mine.send(:construct_finder_sql,{}) + " additional = 'foo'"
}
sure why not
:named_scope :conditions => [ your sql ]