I am storing product information, including the release year of the product, using hstore and postgresql in rails. Now I would like to be able to query for all products that was released before or after a specific year. I am able to query for all records containing the year field in the 'data' hstore column using:
Product.where("data ? 'year'")
Due to hstore the year value is stored as a string. Therefore, I have tried to type cast the year to an integer in order to find records with years greater than/less than X:
Product.where("(data ? 'year')::int > 2011")
However, this does not seem to work, I always get an empty array of results in return. What am I doing wrong? Is there another way to do this?
I think the operator your are looking for is ->.
So, try this : where("(data -> 'year')::int > 2011")
(from jO3w's comment)
Related
In my model, I have these columns:
customer_invoiced_at: datetime
customer_invoice_at_custom: datetime
I am trying to search all records where the given date matches customer_invoiced_at:
scope :by_customer_invoiced_at_from, (lambda do |date_from|
self.where("customer_invoiced_at >= ?", date_from.to_datetime.beginning_of_day) if date_from.present?
end)
I'd need to tweak it a bit - if customer_invoice_at_custom exists (is not null or empty), I would need to use this field instead of customer_invoiced_at. However, if customer_invoice_at_custom is NULL or empty, I'd want to use customer_invoiced_at (as it is now in the shown scope).
How do I achieve that?
Thank you in advance
Can you use PostgreSQL's native COALESCE() function? This does exactly what you want:
.where("COALESCE(customer_invoiced_at, my_other_column) >= ?", date_from.to_datetime.beginning_of_day)
In my rails psql application I have an emails array column. The element in the first index of this column is the primary email. I want to be able to search the db for all people with primary email x.
No need to test for array inclusion. Just get the first element and compare that to the string:
User.where("emails[1] = ?", "x#test.com")
I could not see this in the documentation but thanks to this answer I can see that in Postgres 9.5 or older you can use
arr[1:1]
syntax to look only in the first element
So this is the answer
User.where("emails[1:1] #> ARRAY[?]", "x#test.com")
I'm migrating a Rails 3.2 app to Rails 5.1 (not before time) and I've hit a problem with a where query.
The code that works on Rails 3.2 looks like this,
sales = SalesActivity.select('DISTINCT batch_id').where('salesperson_id = ?', sales_id)
sales.find_each(batch_size: 2000) do |batchToProcess|
.....
When I run this code under Rails 5.1, it appears to cause the following error when it attempts the for_each,
ArgumentError (Primary key not included in the custom select clause):
I want to end up with an array(?) of unique batch_ids for the given salesperson_id that I can then traverse, as was working with Rails 3.2.
For reasons I don't understand, it looks like I might need to include the whole record to traverse through (my thinking being that I need to include the Primary key)?
I'm trying to rephrase the 'where', and have tried the following,
sales = SalesActivity.where(salesperson_id: sales_id).select(:batch_id).distinct
However, the combined ActiveRecordQuery applies the DISTINCT to both the salesperson_id AND the batch_id - that's #FAIL1
Also, because I'm still using a select (to let distinct know which column I want to be 'distinct') it also still only selects the batch_id column of course, which I am trying to avoid - that's #FAIL2
How can I efficiently pull all unique batch_id records for a given salesperson_id, so I can then for_each them?
Thanks!
How about:
SalesActivity.where(salesperson_id: sales_id).pluck('DISTINCT batch_id')
May need to change up the ordering of where and pluck, but pluck should return an array of the batch_ids
I got a table named companies and a column named employees, which is a string column.
My where condition to find companies which have between 10 and 100 employees:
where("companies.employees >= ? AND companies.employees <= ?", 10, 100)
The problem is: The column needs to remain a string column so I can't just convert it to integer but I also want to compare the employee numbers. Is there any way to do this?
This may work, it is a ruby question, I don't know ruby :-) In postgres I would write the query as Craig says, like this:
select * from companies where employees::integer >= 10 and employees::integer <= 100;
(Of course there is substitution, etc, but this gets the concept across. One of the problems you run in to when you don't use the correct type in postgres is that indices don't work right. Since you are casting the employees to an integer type, you have to fetch every record, convert it to an integer, then filter using the greater/less than stuff. Every record in the table will be fetched, casted, then compared. If this was an integer type to start with, and there was an index on the table, then the postgres engine can do a lot better performance wise by selecting only the relevant records. Anyway...
Your ruby may work modified like this:
where("companies.employees::integer >= ? AND companies.employees::integer <= ?", 10, 100)
But, that makes me curious about the substitution. If the type is gleaned from the type of the argument, then it might work because the 10 and 100 are clearly integers. If the substitution gets weird, you might be able to do this:
where("companies.employees::integer >= cast(? as integer) AND companies.employees::integer <= cast(? as integer)", 10, 100)
You can use that syntax for the entire query as well:
where("cast(companies.employees as integer) >= cast(? as integer) AND cast(companies.employees as integer) <= cast(? as integer)", 10, 100)
One of these variants might work. Good Luck.
-g
I have an AR query that returns a hash of events per month, ordered by month
o.events.group("to_char(date,'MM')").order("to_char(date,'MM')").size()
I'm using numeric months in this query as it was the best way I could find to get things in the correct order, and I also need to do some other manipulations on the hash.
Before display the results, I need to convert the numeric months back to words. I added the following to the end of the query
.each_key{ |key| Date::MONTHNAMES[key] }
But i get
TypeError: can't convert String into Integer.
So i tried
.each_key{ |key| Date::MONTHNAMES[key.to_i] }
But the months remain in numeric form
{"01"=>4, "02"=>3.....
How can i manipulate this hash to get
{"January"=>4, "February"=>3.....
Make a new Hash. If you can't, make a new key in the current hash and delete the original key. You can't simply change a key, since key is a local variable in the block, and changing it in no way impacts the contents of the Hash.
This ? :
def number_to_month(number)
(Time.now.beginning_of_year + number.months).strftime("%B")
end
There are ways to generate a new hash but I think you could just convert the strings to month names in your view right before displaying them. Use the code you already wrote inside the block in your question but put it in your view.