MySQL: Validate for date range within rate range (laravel optional) - php

Hey guys (and girlies)
Can someone point out to validate / search for a date range within a date range? I am using Laravel PHP but raw SQL will be perfect as well.
I want to validate if a date range exists, within a date range. Basically I want a solid validation to avoid overlapping date ranges.
Example (and the concept I have at the moment) (laravel syntax)
->where('start_date','>=',$myrange_start)
->where('start_date','<=',$myrange_end)
Which will validate for for a start date in the database between the date range
and
->where('start_end','>=',$myrange_start)
->where('start_end','<=',$myrange_end)
Which will validate for for an end date in the database between the date range
And which has also kind of worked for me is
->whereRaw('? between start_date and end_date', [$today])
however, what I want to achieve is to say something like
->whereRaw('? between start_date and end_date', [$myrange_start, $myrange_end])
so see if there are date ranges which
a) start: on start, between start and end, on end
b) start: on end
c) end: on start, between start and en, on end
d) start BEFORE start date and ends AFTER ends date
e) start AFTER start date and ends BEFORE end date
Is this possible?

This is the overlapping range problem, and to quote this canonical SO answer, the WHERE clause should be something like:
WHERE new_start < existing_end
AND new_end > existing_start;
Translating this to Laravel code:
->where('start_date', '<', $myrange_end)
->where('start_end', '>', $myrange_start)
This would return true if there is an overlap between the two ranges. If instead you want to find out if there isn't an overlap, then we can try:
->where('start_date', '>=', $myrange_end)
->orWhere('start_end', '<=', $myrange_start)

Laravel official docs laravel docs whereBetween
ModelName::whereBetween('date_field', [ $start_Date, $end_date ])->get();

Okay, think this should then work. you guys can comment
where(function ($q) use ($start, $end) {
$q->where('start_date', '>=', $start)
->where('start_date', '<=', $end);
})
->orWhere(function ($q) use ($start, $end) {
$q->where('end_date', '>=', $start)
->where('end_date', '<=', $end);
})
->orWhere(function ($q) use ($start, $end) {
$q->where('start_date', '<', $start)
->where('end_date', '>', $end);
});

Related

How to add days in querying date? laravel

How can we add days in the date that we're querying using laravel eloquent?
Something like this:
Post::where('created_at + 7 days', now()->toDateTimeString())
->where('created_at', '<', now()->toDateTimeString())
->get();
My logic is like this one
today >= created_at && today <= created_at + 4
Is there some correct syntax to achieve this one?
One of the ways to compare from date time is using the calculated Carbon like below:
Post::where('created_at', '>=', now()->addDays(4)->toDateTimeString()
->get();
It will display only posts which have created_at greater than 4 days from today.
For date range filter, you can use between scope like:
$startDate = now()->subDays(4)->toDateString();
$endDate = now()->toDateString();
$filteredPosts = Post::whereBetween('created_at', [$startDate, $endDate])->get();
For more information about filter, you could visit Laravel Query Builder
You can use whereDate method:
Post::whereDate('created_at', 'like', now()->subDays(4))->get();
or
Post::whereDate('created_at', '>=', now()->subDays(4))->get();

Check date range is not already booked in Laravel 6?

I am working in an online bike booking system where the customer can book a bike for a particular date-time range. If another customer books the same bike for a specified date-time range, I have to check whether the bike is already booked or not. My database table reservations looks like this:
id bike_id start_date end_date
1 1 2019-05-04 14:30 2019-05-04 15:30
1 1 2019-05-04 16:30 2019-05-04 18:30
The query:
Reservations::where('bike_id', $yacht)
->where(function ($query) use ($startTime, $endTime) {
$query->where(function ($query) use ($startTime, $endTime) {
$query->where('start_date', '<', $startTime)
->where('end_date', '>', $startTime);
})
->orWhere(function ($query) use ($startTime, $endTime) {
$query->where('start_date', '>', $endTime)
->where('end_date', '<', $endTime);
});
})
->count();
Unfortunately, the code does not seem to work. It does not check the condition properly. How to do the desired check properly using the given inputs?
Namoshek's answer, based on your code, is correct. Personally, I find all the nested functions hard to read. They're not avoidable in a query like this, but they can be reduced:
$bike = Bike::findOrFail($yacht);
$conflict = $bike->reservations()
->whereBetween('start_date', [$startTime, $endTime])
->orWhereBetween('end_date' [$startTime, $endTime])
->orWhere(fn ($q) => $q->where('start_date', '<', $startTime)->where('end_date', '>', $endTime))
->exists();
if ($conflict) {
abort(409);
}
// continue saving the reservation
I'm assuming that you have correctly set up relations between your Bike and Reservation models, so can take advantage of them to make the code more readable still. (And you'll probably be finding that bike object later in the code anyway.)
What you want to check is whether the start date-time or the end date-time of the new booking lies within any existing record. In other words, there is two cases, as you already identified correctly, where one deals with the start time of the new booking and one with the end time. If any (or both) of them lie within an existing booking, the check failed.
use Illuminate\Database\Eloquent\Builder;
$similarBookingExists = Reservations::query()
->where('bike_id', $yacht)
->where(function (Builder $query) use ($startTime, $endTime) {
$query->where(function (Builder $query) use ($startTime) {
$query->where('start_date', '<=', $startTime)
->where('end_date', '>=', $startTime);
})
->orWhere(function (Builder $query) use ($endTime) {
$query->where('start_date', '<=', $endTime)
->where('end_date', '>=', $endTime);
});
})
->exists();
In short, the only mistake you made were the comparison operators < and > of the second case for $endTime.

eloquent query condition based on relation

Results(game_id, score)
Games(start, end, threshold)
Given a timestamp:
I want to find all results that belong to a game with a start & end time containing the timestamp time and where the result score is above the game threshold.
I have already managed to query for the time condition, but how can I additionally query for Results.score > games.threshold?
Results::whereHas('game', function($q) use ($timestamp) {
$q->where('start', '<=', $timestamp)
->where('end', '>=', $timestamp)
})->with('game')->get()
Try to use whereRaw inside whereHas and check if it works:
Results::whereHas('game', function($q) use ($timestamp) {
$q->where('start', '<=', $timestamp)
->where('end', '>=', $timestamp)
->whereRaw('results.score > games.threshold');
})->with('game')->get();

Laravel - Get row that has today between begin and end

I have a table that has two dates fields, begin and end.
I'm trying to get all rows that have begun but not yet ended. and if today is less than begin, they shouldn't be included. and if today is grater than end they shouldn't be included.
I'm using laravels eloquent. Here is what i've tried
$now = \Carbon\Carbon::now();
$promos = \App\Models\LivePromo::
where("begin", "<=", $now)
->where("end", ">=", $now)
//Other conditions
->get();
This seemingly work, but it also selects rows that are greater have already ended.
How can i make this work as i expect?
EDIT
The begin column is a datetime column that signifies when the 'promo' should start, and the end column is a datetime column that signifies when the 'promo' should end. I'm just trying to get all valid promos for the current date and time
EDIT
Sample data
$now = '2017-02-24 10:29:10' // \Carbon\Carbon::now();
remove = from end date condition:
$now = \Carbon\Carbon::now();
$promos = \App\Models\LivePromo::
where("begin", "<=", $now)
->where("end", ">", $now)
->get();
Also, it might depend on your database engine.
Some engines require you to use the whereDate() method instead of plain old where()
$promos = LivePromo::whereDate("begin", "<=", $now)
->whereDate("end", ">", $now)
->get();

Laravel - Advanced Carbon Date Query

I'm trying to write a certain query but I'm failing with it and I'm looking for some help
Here's what I want to do
SELECT all items WHERE created_at is from before this month (July, June,...), and also select the first 3 which are created during this month
this is what I currently have. I've tried numerous times, but I can't figure out the right "WHERE" case
$offertes = DB::table('offertes')
->select('*')
->where('receiver_id', $user_id)
...
->orderby('seen')
->orderby('created_at','desc')
->get();
Something like this should work:
$time = new Carbon\Carbon('first day of this month'); // Get first day of the month.
$time->setTime(0, 0, 0); // Set time to 00:00:00.
....
->where('created_at', '<', $time)
->where(function($q) {
$q->where('created_at', '>', $time)
->orderby('created_at','asc')
->take(3)
})
->get;

Categories