Sql where t.date attribute is less than current year - sql

In my Rails 3 app, I'm attempting to do a find of current students by their school's name and their graduation date in relation to the current year. I can do a successful find for users without a graduation date (see below), but I want to search users who have a graduation date attribute less than - or greater than - the current year. FYI, I'm using PostgreSQL.
The fields I'm using are set up as follows:
t.string :high_school
t.date :hs_grad_year
Here's the find I have working currently:
<%= pluralize(Profile.where(:high_school => "#{#highschool.name}").where("hs_grad_year IS NOT NULL").count, "person") %>

There's a couple issues with your code (getting records from your database should be done in the controller, not in the view, and you're using high school names as foreign keys instead of an id field, for example), but to answer your question:
Profile.where %'
high_school = ? AND
EXTRACT(year FROM hs_grad_year) < EXTRACT(year FROM current_date)
',
#highschool.name

You want a .where("hs_grad_year < extract(year from current_date)") in there.
In Postgres, current_date is the current date (yyyy-mm-dd), and the extract function pulls just one part of that date out of it. You can read more about date and time functions in Postgres here.

Profile.
where(:high_school => #highschool.name).
where("hs_grad_year < ? OR hs_grad_year > ?", Date.today.year, Date.today.year)

Related

Pagination based on time

I have a PostgreSQL database with posts and I am trying to implement pagination for it.
The table looks like this:
postid | title | author | created
where created has the type timestamp without timezone.
My query looks like
SELECT * from posts
WHERE extract(EPOCH FROM created) < :limit
ORDER BY created DESC
LIMIT 3
Here :limit is a long in java which I pass as a parameter.
However, I always retrieve the same three newest posts, even if I have a limit smaller than the timestamp of the three posts. So I guess that the extract(EPOCH FROM created) part is wrong but I do not know how to fix it.
Your code looks fine, and should do what you want, provided that :limit is really what you think it is.
I would, however, suggest moving the conversion to the right operand rather than converting the stored value to epoch. This is much more efficient, and may take advantage of an index on the timestamp column:
SELECT *
from posts
WHERE created < date'1970-01-01' + :limit * interval '1 second'
ORDER BY created DESC
LIMIT 3
Or:
WHERE created < to_timestamp(:limit::bigint)
A possible problem is that :limit is given in milliseconds rather than seconds. If so:
WHERE created < to_timestamp((:limit/1000)::bigint)

What is a good way to return a text field in a query for a calculated column?

I have an SQLite database with a members table on it. The columns on my table are first_name, last_name, date_dues_paid. I need to return a fourth column labeled active which would either be “true” or “false” depending on if date_dues_paid is a year old or more.
I’ve tried CAST(WHEN ) AS active and used DATEDIFF() and several other methods but just can’t get it right. I can provide more samples and code base later today, posting on mobile right now.
Just add one year to date_dues_paid and compare it against the current date like this:
SELECT
first_name,
last_name,
date_dues_paid,
SELECT CASE WHEN DATE(date_dues_paid,'+1 year') > DATE('now') THEN 'TRUE' ELSE 'FALSE' END AS active
FROM members
Instead of TRUE/FALSE strings you could also use bool (1,0) as a result:
SELECT DATE(date_dues_paid,'+1 year') > DATE('now') AS active

How to filter results based on year in date field in Oracle SQL?

So I'm writing a program which, when given user input, (using JDBC), of a year will return all the orders of that given year. I'm storing the date as 'OrderPlaced' in my Orders table with format 'dd-MMM-YY'. However, I'm a bit stumped how to go about retrieving the information based solely on the year of entry. Would it be with the use of a LIKE statement? or is there an in-built way in which I could filter dates in oracle?
Thanks in advance :)
Don't use LIKE with dates. Here are three alternatives:
where to_char(order_placed, 'YYYY') = :year
where extract(year from order_placed) = :year
where order_placed >= to_date(:year || '0101', 'YYYYMMDD') and
order_placed < to_date(:year + 1 || '0101', 'YYYYMMDD')
The third has the advantage that it is most likely to use an available index on year_of_entry.

Eloquent / DB get months between two dates

I'm using Laravel 5.4.
I have a Booking model which contains a start_date and an end_date. The user chooses a month from a dropdown list.
I would like Eloquent to return all records where the month is between the boundaries of the start_date and end_date.
e.g Show all Bookings that are in September (even if the booking started before (or during September) AND (boolean) ends in September or later.
Any suggestion would be welcome. Happy for this to be a raw SQL statement if needs be.
This is what worked for me:
$start = Carbon::now()->addMonth(-1);
$end = Carbon::now()->addMonth();
$bookings = Booking::whereRaw('MONTH(created_at) > :0 AND MONTH(created_at) < :1',[
$start->month, $end->month
])
->orWhereRaw('MONTH(created_at) = :3 AND DAYOFMONTH(created_at) >= :4', [
$start->month, $start->day
])
->orWhereRaw('MONTH(created_at) = :5 AND DAYOFMONTH(created_at) <= :6', [
$end->month, $end->day
])
->get();
If you want to exclude the start and end dates you can replace >= with > and <= with <.
And ofcourse, you have to change the $start and $end dates. They should be Carbon\Carbon objects.
First, on client side or server side parse the users picked month to something like:
$selected = "2017-09";
Then:
Booking::where([
['start_time','>', $selected],
['end_time','<', $selected]
])->get()
This seems to work:
$bookings = DB::table('bookings')
->whereMonth('start_date', '<', $date->month)->whereMonth('end_date', '>=', $date->month)
->orWhere(function($query) use ($date) {
$query->whereMonth('start_date', $date->month);
})->get();
Should be pretty straightforward.
I'm not sure what format the "month" is in but you should use DateTime::createFromFormat() to get your DateTime object. Feel free to use Carbon if you are familiar. I find for simple things like this, it's adding unnecessary complexity.
Then query using it.
Booking::whereBetween($dateTime->format('Y-m-00'), [DB::raw('start_date'), DB::raw('end_date')])->get();
Adding some explain :
Booking::whereRaw("(start_date, end_date) overlaps (date '2021-06-01', date '2021-06-30')")->get();

Closest day in array sql

I'm trying to find a record and order it by the closets day based on the current day.
Let me try to illustrate with an example.
Say that John wants to find out when he has to teach next. John teaches the following days (days are converted to numbers, where 0 = Sunday, 1 = Monday ...) [1,2]. The current day is Friday (5) and so the result should be 1.
Another example:
Karen wants to figure out when she has to teach next. Karen teaches the following days [0,2,3]. The current day is Thursday (4) and so the result should be 0.
Current query:
TeamOverview.where(coach: current_user.id).order(:day = [next closets day missing here])
Model:
t.string :name
t.integer :coach
t.int :day
Possible records in model:
id: 1, name: John, day: 1
id: 2, name: John, day: 2
id: 3, name: Karen, day: 0
id: 4, name: Karen, day: 2
id: 5, name: Karen, day: 3
To avoid a complex solution I'd rather select all working days and do the work in ruby. Max number of results from query is 7 - that should be fine. Additionally changes are high that you already have such a query (maybe scoped on TeamOverview), you can reuse this and on a second call it may also come from query cache.
working_days = TeamOverview.where(coach: current_user.id).pluck(:day)
working_days.find { |day_num| day_num > today_num } || working_days.first
For getting the next day sorted top you will need to order by distance from current day.
Unfortunately, the %(modulo operator with postgresql keeps the sign
for negative values. Thus, you can not use day - current_day.
But the ordering on following expression will sort the rows according to your intened logic:
(7 + day - current_day) % 7
WHere day is the day form the model row and current_dayis the value for the current day to use with the calculation.
If you prefer a more explicit solution you might turn to
CASE WHEN day < current_day THEN 7 + day - current_day ELSE day - current_day END
(res =TeamOverview.where(coach: current_user.id).order("day").find(:first, :conditions => [ "(day > ? )",current_day]) ) ? res : TeamOverview.where(coach: current_user.id).order("day").find(:first, :conditions => [ "(day < ? )",current_day])
This will give you desired result
You can achieve this in pure SQL with a two-part ordering:
SELECT *
FROM team_overviews
ORDER BY day < (current_day), day
A simple implementation in ActiveRecord for this is:
TeamOverview
.where(coach: current_user.id)
.order("day < #{current_day}")
.order(:day)
Or, if you prefer:
TeamOverview
.where(coach: current_user.id)
.order("day < #{current_day}, day")
Warning: The above code is potentially vulnerable to SQL injection. Be sure that you trust the source of current_day, and sanitise (in this case, probably just call to_i) if necessary.
Unfortunately, looking at the rails source code (as of the current 4.2.6 version at time of posting), it looks as though the ? syntax is not supported by the order ActiveRecord method - i.e. the following is invalid: TeamOverview.order("day < ?", current_day). Perhaps that would be a good addition to the library.
Following code will find next upcoming day, if you need days then remove .first argument
next_day = TeamOverview.where("day > ? and coach_id = ?", current_day, current_user.id).order("day").first