Sort by condition - laravel

I'm new to laravel
I'm busy with a query to get Groups and Items ( separate models but linked )
I want to do the same as was don't for items and that is to order by $sortColumn if not null else sort by description
I'm unsure how t implement this in the given query to replace the ->orderBy('description', 'asc') with the condition.
return $this->model->with( [ 'items' => function($query){
$query->orderBy(\DB::raw("CASE WHEN ".$sortColumn." IS NOT NULL THEN ".$sortColumn."::text ELSE description END"));
}])
->where("hos_id",$hos_id)
->orderBy('description', 'asc')
->get();
I was thinking maybe
->orderBy(\DB::raw("CASE WHEN ".$sortColumn." IS NOT NULL THEN ".$sortColumn."::text ELSE description END"));
instead of
->orderBy('description', 'asc')

I guess simply
...
->orderBy(DB::raw('CASE WHEN ...'))
...

Related

Laravel JOIN with JSON string

I have two tables in Laravel, one is the comment table, and the second is the users table. In the comment table, I have this type of data.
For this comment table, I want to match the tags column's userid in JSON, so how can we join that userid with the user's table? here is what I tried, but that is not working as expected.
$messages = TopicComment::where('user_id', $currentUserId)
->join("users", "users.id", "=", "users.id")
->(function ($query) {
$query->whereJsonContains('tags.userid', users.id);
})
->
->get()->toArray();
with this package you can create a relation via a json field
https://github.com/staudenmeir/eloquent-json-relations
First, there seem to be a number of errors in your code.
Judging from the DB schema, there is no user_id column in your comments table and so, ::where('user_id', $currentUserId) will not work.
A similar issue occurs in your join statement. You're joining on "users.id","=","users.id" which is the same column in the same table.
There's no method called in the line with function($query). Ideally, should be a where clause.
Correct usage of whereJsonContains would be:
$query->whereJsonContains('tags', ['userid' => $currentUserId]);
Rouge arrow after that line.
And so, your final result after correcting the changes should look like:
use Illuminate\Support\Facades\DB;
...
$messages = TopicComment::join('users', 'users.id', DB::Raw("CAST(comments.tags->'$.userid' AS UNSIGNED)"))
->where(function ($query) use ($currentUserId) {
$query->whereJsonContains('tags', ['userid' => $currentUserId]);
})
->get()
->toArray();
I think the only way to extract is to use json tables.
DB::select(DB::raw("
SELECT document_types.*, jst.name
FROM document_types,
JSON_TABLE(settings, '$[*]' COLUMNS (
`userid` int(11) PATH '$.userid',
`name` varchar(255) PATH '$.name'
)) jst
inner join users on jst.userid = users.id WHERE users.id = :id"
,['id' => $currentUserId]))->get()
credit: https://dba.stackexchange.com/questions/306938/extract-json-object-inside-of-an-json-array-then-search-base-on-id
Unfortunately I don't have json functions on my mysql so the code will probably fail, maybe at least it'll help get you on the right track.
You can try this way...
eg:
<?php
$comments = DB::table('topic_comments')
->join('users', 'users.id', '=', 'topic_comments.tags->userid')
->select('topic_comments.*', 'users.name')
->get();

Laravel Query Builder Foreach Loop how do I reference a field that exists in both join tables

The id field in the foreach loop exists in both of the tables that I am joining, I need to reference it to one table only (ie. program_types.id) in the foreach loop:
$program_details = DB::table('program_allocation')
->where('twilio_wa_from_no', '=', $tophonenumber)
->where('twilio_sid' , $account_sid)
->join('program_types', 'program_allocation.program_type', '=', 'program_types.id')
->get();
foreach ($program_details as $program) {
$program_allocation_id = $program->id;
}
You can use select('program_allocation.*', 'program_types.id AS program_type_id') to specify which columns of which tables included in query you want to use.
$program_details = DB::table('program_allocation')
->where('twilio_wa_from_no', '=', $tophonenumber)
->where('twilio_sid', $account_sid)
->join('program_types', 'program_allocation.program_type', '=', 'program_types.id')
->select('program_allocation.*', 'program_types.id AS program_type_id')
->get();
You can check it on official Laravel documentation: https://laravel.com/docs/9.x/queries#inner-join-clause
Select field and give one of the join table id an alias
$program_details = DB::table('program_allocation')
->join('program_types', 'program_allocation.program_type', '=', 'program_types.id')
->select('program_types.*', 'program_allocation.id as allocationID', )
->where('twilio_wa_from_no', '=', $tophonenumber)
->where('twilio_sid' , $account_sid)
->get();

I want to find the value who exist in array

I have 2 queries and I would like to know the elements (date_debut) of the second query which exists in the first query (dateincal). The elements of the second query can appear one or more times in the first query.
once the dates (date debut) (dateincal) have been found i want to be able to then retrieve also the other information for the element found
$feries = Jourferie::Select('dateincal', 'description')
->where('dateincal', '>=', Carbon::now()->startOfMonth())
->where('dateincal', '<=', Carbon::now()->endOfMonth())
->get();
$plannings = Planning::Select('date_debut', 'id', 'agent_id', 'site_id')
->where('id', '!=', 0)
->where('statut', 'provisoire')
->get();
I don't know if that way can help you:
foreach($feries as $ferie){
$myresult = $plannings->contains('date_debut',$ferie->dateincal)
/* do things */
}

Laravel - Unknown column 'subscription_date' in 'group statement'

I want to perform aggregate function and achieve a specific result that group by date, removing time from datetime.
Whenever I group by created_at the error will not be there but it will group by datetime and the result will not be accurate.
I have this query:
Your query seems correct but I think you forgot to retrieve the as keyword,
$revenuereports = DB::table('cloudsubscriptions as c')
->select(
'c.service_name',
DB::raw('COUNT(*) as total_users'),
DB::raw('SUM(c.amount) as total_amount'),
DB::raw('DATE(c.created_at)as subscription_date') // you forgot as here
)
->groupBy('subscription_date')
->orderByRaw('c.created_at DESC');
$render=[];
if(isset($request->start_date) && isset($request->end_date))
{
$revenuereports=$revenuereports->whereBetween('created_at',[$request->start_date,$request->end_date]);
$render['start_date']=$request->start_date;
$render['end_date']=$request->end_date;
}elseif(isset($request->start_date))
{
$revenuereports=$revenuereports->where('created_at',$request->start_date);
$render['start_date']=$request->start_date;
}
if(isset($request->service_name))
{
$revenuereports=$revenuereports->where('service_name','like','%'.$request->service_name.'%');
$render['service_name']=$request->service_name;
}
//dd($revenuedetails->toSql());
$revenuereports= $revenuereports->orderBy('created_at','DESC');
$revenuereports= $revenuereports->paginate(15);
$revenuereports= $revenuereports->appends($render);
$data['revenuereports'] = $revenuereports;
return view('report.revenueReport',$data);
I expect to have a result to filter by subscription_date (without time)
"SQLSTATE[42S22]: Column not found: 1054 Unknown column 'subscription_date' in 'group statement' (SQL: select count(*) as aggregate from cloudsubscriptions as c where created_at between 2019-01-01 and 2019-06-30 group by subscription_date) "
How do I resolve it please?
Do you have the field in database?
Then you should forgot to add as just before subscription_date
$revenuereports = DB::table('cloudsubscriptions as c')
->select('c.service_name', DB::raw('COUNT(*) as total_users'), DB::raw('SUM(c.amount) as total_amount'),DB::raw('DATE(c.created_at) as subscription_date'))
->groupBy('subscription_date')
->orderByRaw('c.created_at DESC')
->get();
BTW, i dont think you need a table alias for this query.
$revenuereports = DB::table('cloudsubscriptions')
->select('service_name', DB::raw('COUNT(*) as total_users'), DB::raw('SUM(amount) as total_amount'),DB::raw('DATE(created_at) as subscription_date'))
->groupBy('subscription_date')
->orderBy('created_at', 'desc')
->get();
You can change your mysql strict->false and try.
You will find it on, config/database.php > connections > strict (default it is true, just change it to false.)
Your query seems correct but I think you forgot to retrieve the as keyword,
$revenuereports = DB::table('cloudsubscriptions as c')
->select(
'c.service_name',
DB::raw('COUNT(*) as total_users'),
DB::raw('SUM(c.amount) as total_amount'),
DB::raw('DATE(c.created_at)as subscription_date') // you forgot as here
)
->groupBy('subscription_date')
->orderByRaw('c.created_at DESC')
->get();

Querying related table data with Eloquent

i have a problem trying to get records from a model based on a related table.
I have two tables one called leads and one called recycle_logs, my app will basically send the same record in the leads table like once a month, and when it does so i'll store a new record in recycle_logs.
The problem is that i need to select all leads with a specific campaign_id value and that have a specific status that is different from invalid, so far so good, now the problem is i need to get them only if they don't have any recycleLogs associated with them OR if the last recycleLog associated with that particular lead is older than 30 days ago for instance.
What i currently have looks somewhat like this.
$leads = $this->leadModel->where(Lead::CAMPAIGN_ID, $this->campaignID)
->where(Lead::DUPLICATED, Lead::DUPLICATED_NO)
->where(Lead::LEAD_STATUS, "!=" ,Lead::LEAD_STATUS_INVALID)
->orderBy(Lead::CREATED_AT, 'desc')
->with(
['leadRecyclingLog' => function($query) {
$query->where(LeadRecyclingLog::CREATED_AT, '<', (new Carbon())->subDays($this->configRecyclingDays))
->orWhere(LeadRecyclingLog::ID, null);
}]
)
->get();
What exactly am i doing wrong? It always selects the same number of records regardless of me adding or removing recycleLogs
I've managed to get it done through a raw SQL query which i'll post below in case it helps anyone, i'd still like to know how to do it in Eloquent/Query Builder.
SELECT * FROM `leads` LEFT JOIN `lead_recycling_logs` ON `leads`.`guid` = `lead_recycling_logs`.`original_lead_guid` WHERE `leads`.`campaign_id` = :campaignID AND `leads`.`duplicated` = 0 AND `leads`.`lead_status` != :invalidStatus AND (`lead_recycling_logs`.`id` IS NULL OR `lead_recycling_logs`.`created_at` < :recyclingDate) ORDER BY `leads`.`created_at` DESC
Try this:
$leads = $this->leadModel->where(Lead::CAMPAIGN_ID, $this->campaignID)
->where(Lead::DUPLICATED, Lead::DUPLICATED_NO)
->where(Lead::LEAD_STATUS, "!=" ,Lead::LEAD_STATUS_INVALID)
->orderBy(Lead::CREATED_AT, 'desc')
->where(function($q) {
$q->whereHas('leadRecyclingLog', function($q) {
$q->where(LeadRecyclingLog::CREATED_AT, '<', (new Carbon())->subDays($this->configRecyclingDays));
})
->orWhereHas('leadRecyclingLog', '<', 1); // Where count of the relationship is smaller than 1
})->get();
I assumed the first part of the query is working well (up until the relationship).
What you're looking for is ->whereHas(relationship), not ->with(relationship). ->with(relationship) will attach the associated results to the original model (the query for the original model will not be affected by ->with()). ->whereHas(relationship) filters the original model by the condition.
Got it to work through #devk 's help
$leads = $this->leadModel->where(Lead::CAMPAIGN_ID, $this->campaignID)
->where(Lead::DUPLICATED, Lead::DUPLICATED_NO)
->where(Lead::LEAD_STATUS, "!=" ,Lead::LEAD_STATUS_INVALID)
->orderBy(Lead::CREATED_AT, 'desc')
->where(function($q) {
$q->whereHas('leadRecyclingLog', function($q) {
$q->where(LeadRecyclingLog::CREATED_AT, '<', (new Carbon())->subDays($this->configRecyclingDays));
})
->doesntHave('leadRecyclingLog', 'or');
})->get();

Resources