How check range beetwen to dates and make comparison in sql on ruby? - sql

.joins(:residence) .where('(custom_services.date_from - ?) <= 1', Date.today)
Does anyone know how to correctly implement a check the difference between the date in custom_services.date_from and today's is less than or equal to one day(in the screenshot, one of the attempts is not correct)

Using Date.tomorrow and beginless range:
.where(date_from: ..Date.tomorrow)
if need to specify table name
.where('custom_services.date_from': ..Date.tomorrow)

you can just use
.where('custom_services.date_from <= ?', Date.today + 1.day)

Can you use something like this?
where("DATEDIFF(custom_services.date_from, ?) <= 1", Date.today)

Related

Selecting entries whose `date_field < NOW()`

When I try to run the following query, it returns nothing:
Item::where(\DB::raw('date_field < NOW()'))->get()
The reason for this is, that is null is appended to the generated MySQL query like this:
SELECT * FROM items WHERE date_field < NOW() is null;
Why does the is null part get appended to the above query?
This is a known issue in Laravel and has been reported on their GitHub page. Use whereRaw() instead and pass a string:
Item::whereRaw('date_field < NOW()')->get()
No idea why the not null part gets appended. But I found a workaround.
Try this
Item::whereNotNull(\DB::raw('date_field < NOW()'))->get()
Of course, you may use built-in features like Carbon
Item::where('date_field', '<', Carbon\Carbon::now())->get()
Use it this way..
Item::where('date_field','<','NOW()')->get()
SELECT * FROM items WHERE date_field < GETDATE();

RoR Search conditions comparing two columns

What I basically want to do is the following:
a = Assignment.all(:conditions => { :end_date < :start_date })
I only want to select those records on which the end_date is before the start_date.
I actually don't want ending up writing a
for each, push to array if end_date is earlier than start_date.
How can I achieve this in a pretty 'Railsy'-way?
Thank you in advance.
Edit:
I think the problem is comparing the values of both columns. (Allmost) every query is comparing a cell-value to an input-value.
This is a shot in the dark, but maybe one in the right direction ?
Haven't figured out a solution.
It's been a while here but nevertheless, you can just use the ArelTable method:
t = Assignment.arel_table
Assignment.where(t[:end_date].lt(t[:start_date]))
The condition predicates documentation: http://www.rubydoc.info/github/rails/arel/Arel/Predications
The ArelTable documentation: http://www.rubydoc.info/github/rails/arel/Arel/Table
And a good guide: http://jpospisil.com/2014/06/16/the-definitive-guide-to-arel-the-sql-manager-for-ruby.html
a = Assignment.all(:conditions => ["end_date < ?", :start_date ])
Check this: http://api.rubyonrails.org/classes/ActiveRecord/FinderMethods.html#method-i-all
I am assuming that you are using ActiveRecord
try
a = Assignment.where('regioassignments.end_date < regioassignments.start_date')
use the tablename followed by the EXACT COLUMNNAMES in the database, since ActiveRecord recognizes this and uses this as SQL directly.
That means the columnname for end_date is probably assignment_expected_end_date from what I figured from one of your comments.
adapted from this answer

Rails / Postgres: “must appear in the GROUP BY clause or be used in an aggregate function”

I'm using this method:
def self.lines_price_report(n)
Income.group('date(filled_at)').having("date(filled_at) > ?", Date.today - n).sum(:lines_price)
end
I'm getting this error in Heroku:
PG::Error: ERROR: column "incomes.filled_at" must appear in the GROUP BY clause
or be used in an aggregate function
How can I fix this? Thank you.
Executed query:
SELECT SUM("incomes"."lines_price") AS sum_lines_price, date(filled_at)
AS date_filled_at FROM "incomes"
HAVING (date(filled_at) > '2012-12-04')
GROUP BY date(filled_at) ORDER BY filled_at ASC
Expected result
[["2012-12-04", SUM_FOR_DATE], ["2012-12-05", SUM_FOR_DATE], ...]
Your mistake was to use filled_at in order by probably in default scope.
You can fix it using unscoped to eliminate default scopes:
Income.unscoped
.group('date(filled_at)')
.having("date(filled_at) > ?", Date.today - n)
.sum(:lines_price)
or
Income.unscoped
.group('date(filled_at)')
.having("date(filled_at) > ?", Date.today - n)
.sum(:lines_price)
.order('date(filled_at) ASC')
but I think that better will be to use where instead of having
Income.unscoped
.where("date(filled_at) > TIMESTAMP ?", Date.today - n)
.group('date(filled_at)')
.sum(:lines_price)
.order('date(filled_at) ASC')
SQLFiddle
You have to be careful about using TIMESTAMP because 2012-12-04 will become 2012-12-04 00:00:00 so if you don't want this day in result use Date.today - (n - 1)
If you create index on filled_at column
create index incomes_filled_at on incomes(filled_at);
migration:
add_index :incomes, :filled_at
and you have a lot of data in this table index will be used in filtering. So query should be much faster.
So just write both and test which is faster (you have to create index on filled_at if you don't have one).
I guess this is because you use date(filled_at) in GROUP BY but just filled at in ORDER. As I guess order is taken from default scope you need to overwrite it by reorder. I would suggest:
Income.sum(:lines_price).
group('date(filled_at)').
having("date(filled_at) > ?", Date.today - n).
reorder("date(filled_at) ASC")
When you want to use Group By on PostgreSQL, The select option should be required on the group by.
Income.select('filled_at').group('date(filled_at)').having("date(filled_at) > ?", Date.today - n).sum(:lines_price)

Rails 3 query in multiple date ranges

Suppose we have some date ranges, for example:
ranges = [
[(12.months.ago)..(8.months.ago)],
[(7.months.ago)..(6.months.ago)],
[(5.months.ago)..(4.months.ago)],
[(3.months.ago)..(2.months.ago)],
[(1.month.ago)..(15.days.ago)]
]
and a Post model with :created_at attribute.
I want to find posts where created_at value is in this range, so the goal is to create a query like:
SELECT * FROM posts WHERE created_at
BETWEEN '2011-04-06' AND '2011-08-06' OR
BETWEEN '2011-09-06' AND '2011-10-06' OR
BETWEEN '2011-11-06' AND '2011-12-06' OR
BETWEEN '2012-01-06' AND '2012-02-06' OR
BETWEEN '2012-02-06' AND '2012-03-23';
If you have only one range like this:
range = (12.months.ago)..(8.months.ago)
we can do this query:
Post.where(:created_at => range)
and query should be:
SELECT * FROM posts WHERE created_at
BETWEEN '2011-04-06' AND '2011-08-06';
Is there a way to make this query using a notation like this Post.where(:created_at => range)?
And what is the correct way to build this query?
Thank you
It gets a little aggressive with paren, but prepare to dive down the arel rabbit hole
ranges = [
((12.months.ago)..(8.months.ago)),
((7.months.ago)..(6.months.ago)),
((5.months.ago)..(4.months.ago)),
((3.months.ago)..(2.months.ago)),
((1.month.ago)..(15.days.ago))
]
table = Post.arel_table
query = ranges.inject(table) do |sum, range|
condition = table[:created_at].in(range)
sum.class == Arel::Table ? condition : sum.or(condition)
end
Then, query.to_sql should equal
(((("sessions"."created_at" BETWEEN '2011-06-05 12:23:32.442238' AND '2011-10-05 12:23:32.442575' OR "sessions"."created_at" BETWEEN '2011-11-05 12:23:32.442772' AND '2011-12-05 12:23:32.442926') OR "sessions"."created_at" BETWEEN '2012-01-05 12:23:32.443112' AND '2012-02-05 12:23:32.443266') OR "sessions"."created_at" BETWEEN '2012-03-05 12:23:32.443449' AND '2012-04-05 12:23:32.443598') OR "sessions"."created_at" BETWEEN '2012-05-05 12:23:32.443783' AND '2012-05-21 12:23:32.443938')
And you should be able to just do Post.where(query)
EDIT
You could also do something like:
range_conditions = ranges.map{|r| table[:created_at].in(r)}
query = range_conditions.inject(range_conditions.shift, &:or)
to keep it a little more terse
I suggest you try the pure string form:
# e.g. querying those in (12.months.ago .. 8.months.ago) or in (7.months.ago .. 6.months.ago)
Post.where("(created_at <= #{12.months.ago} AND created_at >= #{8.months.ago} ) OR " +
"(created_at <= #{7.months.ago} AND created_at >= #{6.months.ago} )" )
In your case, I would suggest to use mysql IN clause
Model.where('created_at IN (?)', ranges)

Is there a way to update an entire array or named_scope without using a loop in ruby on rails?

I create the following array using searchlogic named_scopes:
todos = Todo.asset_is("Email").asset_id_is(self.id)
For each value in the array, there is an attribute called original_date and current_date.
I need to make changes to those with some logic, such as:
difference = (original_date - date_entered) - self.days
original_date = date_entered + self.days
current_date = current_date - different
What I do not want to do is do an each do-loop. But I don't know if there's an alternative -- something like the "update" in SQL (but without needing to use SQL -- like using searchlogic)
Todo.update_all(["original_date = date_entered + %d, current_date = ... + %d",
self.days, self.days], ["id in (?)", todos.map(&:id)])