I have a PostgreSQL query that sums values by month, extracting the month value from a date:
SELECT vendors.name AS vendor,
SUM(purchases.invoice_total) AS invoice_total,
EXTRACT(MONTH FROM purchases.date) AS date
FROM vendors, purchases
WHERE purchases.vendor_id = vendors.id
AND purchases.store_id = ?
AND purchases.purchase_department_id = ?
AND (purchases.date BETWEEN ? AND ?)
GROUP BY vendor, EXTRACT(MONTH FROM purchases.date)
ORDER BY vendor, date;
After executing the query directly in the DB console, I get something like this:
+------------------------------------+---------------+------+
| vendor | invoice_total | date |
+------------------------------------+---------------+------+
| Store 1 | 448.56 | 1 |
| Store 1 | 263.44 | 2 |
| Store 1 | 939.47 | 3 |
The problem comes when using Rails' find_by_sql
function. The vendor
and invoice_total
values get returned correctly, but the date values get returned as nil.
#<Purchase date: nil, invoice_total: #<BigDecimal:85c75c8,'0.26344E3',18(18)>>
This is my call. I've even tried with hardcoded values and nothing, but it's like the Extract function won't execute in Rails:
<% @purchasesSQL = Purchase.find_by_sql(["SELECT vendors.name AS vendor, SUM(purchases.invoice_total) AS invoice_total,
EXTRACT(MONTH FROM purchases.date) AS date
FROM vendors, purchases
WHERE purchases.vendor_id = vendors.id
AND purchases.store_id = ?
AND purchases.purchase_department_id = ?
AND (purchases.date BETWEEN ? AND ?)
GROUP BY vendor, EXTRACT(MONTH FROM purchases.date)
ORDER BY vendor, date;", @store.id, purchase_department.id, @start, @end])
%>
I've already done some debugging and the values I'm passing are not nil nor wrong.
You say that you have a column named date
in your Purchase
model's table (that's a terrible name for column BTW, using type names for column names just leads to pain and suffering). Presumably your date
column is a date
or timestamp
. In your Purchase.find_by_sql
, you have this:
EXTRACT(MONTH FROM purchases.date) AS date
and Purchase.find_by_sql
will be trying to create Purchase
instances. So you're giving Purchase
a simple number and calling it date
, Purchase
probably notices that it has a date
column and tries to parse your simple number as a full date or timestamp. A simple number cannot be parsed as a date or timestamp in any meaningful fashion so they're probably all get converted to nil
.
You have two things to do here:
date
column to something else, something that doesn't conflict with any keywords.And to hopefully fix your immediate problem, use a different alias for your month number:
EXTRACT(MONTH FROM purchases.date) AS month_number
That should get you a month_number
method on the returned Purchase
objects.