Laravel - query the same column with two conditions - mysql

I want to get all the datas that were created 30-365 days ago. Tried following codes but it's not working.
Database:
id created_at
1 2022-05-09
2 2021-06-08
Here id 2 was created before 365 days from today(2022-06-10), so it should not be shown. However id 1 was created before 30 days but not more than 365 days. So only id 1 should be shown.
Code 1:
$today = Carbon::now();
$doubtfulLoan = Loan::select('*')
->where(function($query) use ($today) {
return $query
->where('created_at', '<', $today->subDays(30)->endOfDay())
->where('created_at', '>=', $today->subDays(365)->endOfDay());
})
->get();
Output: it gives empty array
P.S if the 2nd where clause is commented, it gives both the ids and if the 1st where clause is commented, it gives id 1 only. But keeping both the condition gives empty array. What am I doing wrong?
Code 2:
$today = Carbon::now();
$doubtfulLoan = Loan::select('*')
->where([
['created_at', '<', $today->subDays(30)->endOfDay()],
['created_at', '>=', $today->subDays(365)->endOfDay()]
])->get();
Output: it gives both the array.
Thanks in advance.

You need to get into the habit of using CarbonImmutable to prevent nasty surprises like this. Use this code:
$today = CarbonImmutable::now();
$doubtfulLoan = Loan::select('*')
->where(function($query) use ($today) {
return $query
->where('created_at', '<', $today->subDays(30)->endOfDay())
->where('created_at', '>=', $today->subDays(365)->endOfDay());
})
->get();
This is because you are doing $today->subDays(30)->endOfDay() which changes the instance value of the carbon instance and then doing $today->subDays(365)->endOfDay() which changes it again. This is however the same instance, so the query builder will do:
SELECT * FROM loans WHERE created_at < '395 days ago' and created_at >= '395 days ago'
since you have passed the same instance. This obviously is never satisfied.
Using the CarbonImmutable class makes all your Carbon objects immutable and any modifications will create a new instance and will not modify the existing instance.

use laravel between method here
$doubtfulLoan = Loan::select('*')
->whereBetween('created_at',[
today()->subDays(365)->startOfDay(),
today()->subDays(30)->endOfDay()
])->get();

Related

Laravel: get models if count of relation has some condition

I have User and UserComplains Models.
I like to retrieve users that have UserComplains more than 2 times in the last 24 hours.
users:
id
user_complains:
complained_id ->ref-> users.id
created_at
this is what I tried and it is working:
$users = User::select('users.*')->join('user_complains' , 'users.id' , '=' , 'user_complains.complained_id')
->whereRaw("(
select count(*) from `user_complains`
where `user_complains`.`complained_id` = `users`.`id`
and `user_complains`.`created_at` > ?) >= ?" , [now()->subHours(24), 2])
->groupBy("users.id")
->get();
the above code is fine and is working, but I wonder is there a better way to do that?!
For something like this you can use whereHas(). :
$users = User::whereHas('*relationship*', function ($query) {
$query->where('created_at', '>=', now()->subDay(1));
}, '>', 2)->get();
As mentioned in the documentation, you can pass additional checks as the 3rd and 4th param so in this case you want to say where the user has more that 2 user_complains.
NB You will need to replace *relationship* with the actual name of the relationship.
You can do the following:
User::whereHas('complaints', function($query) {
$query->where('created_at', '>=', '2020-04-26');
}, '>', 2)->get();
In order for this to work though you need to have set up a relationship between your User and UserComplaint models.
class User extends Model
{
public function complaints()
{
return $this->hasMany(UserComplaint:class);
}
}

MySQL query with DATE_FORMAT() to Laravel Querybuilder (or Eloquent)

I'm trying to get records from a table on a specific day.
Dates's format: datetime (YYYY-MM-DD HH:II:SS)
I'm trying to translate a MySQL query to Laravel query builder. But I don't know how to deal with the DATE_FORMAT().
Here is MySQL query
SELECT * FROM events
JOIN customers ON events.id_customer = customers.id
WHERE start_date > DATE_FORMAT("2017-06-15", "%Y-%m-%d %H:%i:%s")
AND end_date < DATE_FORMAT("2017-06-16", "%Y-%m-%d %H:%i:%s")
;
In my controller I get a date (string) that I put into a DateTime
$date_datetime = new \DateTime(Input::get('date_string'));
And then change its format
$query_date = date_format($date_datetime, 'Y-m-d H:i:s');
I've tried the following code, but it is obviously not working
$pdf_events = DB::table('events')
->join('customers', 'events.id_customer', '=', 'customers.id')
->select(...)
->whereRaw("start_date > DATE_FORMAT($query_date, '%Y-%m-%d %H:%i:%s')")
->whereRaw("end_date < DATE_FORMAT($query_date, '%Y-%m-%d %H:%i:%s')+1")
->get();
I strongly recommend using Carbon for handling DateTime in Laravel since it has support out of the box.
Now, how to use it to resolve your problem?
First, you need to convert your input into Carbon object.
$start_date = Carbon::parse(Input::get('date_string'));
// Assuming you want the end date 1 day later at same time
$end_date = $start_date->addDay();
// You could change the format with format() but in this case we don't need to
Then in your Eloquent, you can use the Carbon Datetime object to query using where()
$pdf_events = DB::table('events')
->join('customers', 'events.id_customer', '=', 'customers.id')
->select(...)
->where("start_date", ">", $start_date)
->where("end_date", "<", $end_date)
->get();
You can pass Carbon (doc) objects to compare dates. For example:
->where('start_date', '=', Carbon::now())
You can build a custom Carbon object for a custom date-time to pass into the where clause.
You don't need DATE_FORMAT, Try this:
$query_start_date = \Carbon\Carbon::createFromFormat("Y-m-d H:i:s", request()->date_string);
// Add 1 day to the date
$query_end_date = $query_start_date->addDay();
$pdf_events = DB::table('events')
->join('customers', 'events.id_customer', '=', 'customers.id')
->where(
[
["start_date", ">", $query_start_date],
["end_date", "<", $query_end_date]
]
)->get();
use Datetime;
$end_date1 = $request->input('end_date');
$EndDateTime = DateTime::createFromFormat('d/m/Y H:i:s', $end_date1);
$end_date = $EndDateTime->format('Y-m-d H:i:s');
try like this its work for me

Laravel - where >= not working

I'm trying to get a database entry with this lines of code:
$hoy = date('YYYY-MM-DD');
$stay = Stay::where('guest', '=', $id )
->where('indate', '<=', $hoy )
->where('outdate', '>=', $hoy )
->get( array( 'id', 'room', 'bed', 'guest', 'booking', 'indate', 'outdate' ) );
The thing is, if I remove the outdate >= $hoy line, it works. But with it, it doesn't.
The line i'm trying to retrieve has it's outdate set to 2015-12-02, so it should return it.
Any ideas?
Looks like this is your problem:
$hoy = date('YYYY-MM-DD');
If you want to generate a date like 2015-12-02, you should do this instead:
$hoy = date('Y-m-d');
Source: http://php.net/manual/en/function.date.php
This query expects both conditions to be true.
If you want to return when either one is true you should try ->orwhere.
If you are looking for both to be true you need to keep in mind that if there are timestamps on the date the query of <= will only find dates with a timestamp of 00:00:00 for the requested date.

Can I update a single row by maximum id using eloquent/fluent

I have the following query:
$row = Notification::where('from_user_id', '=', Auth::id())
->where('to_user_id', 0)->update(['to_user_id' => $obj]);
which works but how do I update just ONE row? I was hoping to use maximum id for example ->max('id') but I've tried numerous ways of implementing but im having no luck. Or could I use timestamps to distinguish uniqueness?
id|from_user_id|to_user_id |created_at|updated_at
1 | 8 | 0 |2015-04-09|2015-04-09
2 | 8 | 0 |2015-04-09|2015-04-09
I'm actually iterating through my $obj variable and so it changes simply because it's part of an array which is why I only want to update just one of the rows.
You can get the last row (based on created_at field):
$row = Notification::where('from_user_id', '=', Auth::id())
->where('to_user_id', 0)
->orderBy('created_at', 'desc')
->first();
And update the to_user_id on that row:
$row->to_user_id = YOUR_TO_USER_ID;
$row->save();
You are missing the '=' sign on second where clause and update values have to be array type, the query should be
$row = Notification::where('from_user_id', '=', Auth::id())
->where('to_user_id','=', 0)->update(array('to_user_id' => $obj));

Multiple wheres in Laravel join

I have:
$buyingNet = DB::table('parts_enquiries_buying AS PEB')
->select(DB::raw('SUM((PEB.quantity*PEB.net)/IF(ISNULL(currencyRate), rate, currencyRate)) AS total'))
->join('currencies_rates AS CR', function ($q) {
$q->on('CR.id', '=', 'PEB.currencyId')
//->where(DB::raw('YEAR(CR.date)'), '=', date('Y'))
->where(DB::raw('MONTH(CR.date)'), '=', date('m'));
})
->leftJoin('jobs', 'jobs.enquiryId', '=', 'PEB.enquiryId')
->leftJoin('invoices_out AS IO', 'IO.jobId', '=', 'jobs.id')
->where('PEB.enquiryId', $enquiryId)
->first()->total;
If I uncomment the where that matches the year I get null returned, but all the rows that should be there are there.
Is my syntax correct? It should translate as:
... YEAR(CR.date) = ? AND MONTH(CR.date) =? ...
I believe the issue here is that Query builder doesn't understand your DB::raw statement within the ->where clause.
You should do as folllows:
->whereRaw("YEAR(CR.date) = '". date('Y')."'")
->whereRaw("MONTH(CR.date) = '". date('n')."'")
for the month clause you need to use n instead of m since MySQL MONTH returns a single digit for months below 10.