getting find_by_sql to return the numeric value rather than an object that contains the value as an attribute

Hey all,

So I have a custom query that I embedded into a class method definition:

def self.get_sum_for_range(unit_id,report1,report2)      find_by_sql(["SELECT SUM(distance * 0.000621371192) as sum FROM reports WHERE unit_id=? AND id >= ? AND id <= ?", unit_id, report1, report2]) end

value = Report.get_sum_for_range(unit.id,report1,report2)

The problem is value will be a report object that contains an attribute called sum with the value, but all I want is just the value itself returned into value.

thanks for response

value = Report.get_sum_for_range(unit.id,report1,report2).sum

def self.get_sum_for_range(unit_id,report1,report2)     find_by_sql(["SELECT SUM(distance * 0.000621371192) as sum FROM reports WHERE unit_id=? AND id >= ? AND id <= ?", unit_id, report1, report2]).sum end

Note the .sum on the end of find_by_sql

Colin

Ah, yeah. Do it in the method.

Is there not a more railsy way of doing what the op wants rather than using find_by_sql? At least it would be more efficient I think to do the * 0.006... after the find.

find_by_sql(["SELECT SUM(distance) as sum FROM reports WHERE unit_id=? AND id >= ? AND id <= ?", unit_id, report1, report2]).sum * 0.000621371192

Colin

def self.get_sum_for_range(unit_id,report1,report2)     find_by_sql(["SELECT SUM(distance * 0.000621371192) as sum FROM reports WHERE unit_id=? AND id >= ? AND id <= ?", unit_id, report1, report2]).sum end

Hmmm... yes, I wonder whether the method is doing too much. That's a conversion to meters from miles, but there's a "unit_id" being passed (and I wonder what the intention of that is)... so it might be better to have a couple of more reusable methods:

def self.get_sum_for_range(unit_id,report1,report2)     find_by_sql(["SELECT SUM(distance) as sum FROM reports WHERE unit_id=? AND id >= ? AND id <= ?", unit_id, report1, report2]).sum end

def self.get_sum_of miles_in_meters(report1,report2)   Report.get_sum_for_range(unit.id,report1,report2) * 0.000621371192 end

value = Report.get_sum_of miles_in_meters(report1, report2)

...but I think this is straying from the topic :slight_smile:

Ah, yeah. Do it in the method.

Is there not a more railsy way of doing what the op wants rather than using find_by_sql? At least it would be more efficient I think to do the * 0.006... after the find.

find_by_sql(["SELECT SUM(distance) as sum FROM reports WHERE unit_id=? AND id >= ? AND id <= ?", unit_id, report1, report2]).sum * 0.000621371192

Hmmm... yes, I wonder whether the method is doing too much. That's a conversion to meters from miles, but there's a "unit_id" being passed (and I wonder what the intention of that is)... so it might be better to have a couple of more reusable methods:

def self.get_sum_for_range(unit_id,report1,report2) find_by_sql(["SELECT SUM(distance) as sum FROM reports WHERE unit_id=? AND id >= ? AND id <= ?", unit_id, report1, report2]).sum end

def self.get_sum_of miles_in_meters(report1,report2) Report.get_sum_for_range(unit.id,report1,report2) * 0.000621371192 end

value = Report.get_sum_of miles_in_meters(report1, report2)

I was thinking more along the lines of removing find_by_sql, something like

Report.where("unit_id=? AND id >= ? AND id <= ?", unit_id, report1, report2).sum('distance')

...but I think this is straying from the topic :slight_smile:

True, but may still be helping the OP.

Colin

+1

I tend to assume that there's some reason they've written the sql that way (like it's to a view, legacy structure that doesn't map to a model, or there's something more to the query and they've just posted a minimum code sample) - and that's probably wrong of me. It the query is *exactly* as posted, then yes, FTLOG change it to a chain of AR clauses/scopes (is that the term for it?!) :slight_smile:

Not related directly to your question but I feel I should point out that there is almost certainly something wrong with your database design if you are using id values to select a range of records. It is not a good idea to use id values for anything other than being a unique value for each record. If you need something like a report_number to be used in the way you are doing here it is generally better to add an extra column for that. Suppose for example that while adding reports you missed one out, using the id there would be no way of going back and inserting one in the range later.

Colin

Using this technique:

Report.where("unit_id=? AND id >= ? AND id <= ?", unit_id, report1, report2).sum('distance')

was ultimately the best solution for me, because using find_by_sql and then calling sum on it would behave unexpectedly, like sometimes the sum would have to be invoked twice: find_by_sql(...).sum.sum

And I replaced id with time to select within time frame