Laravel Query Builder result using join() query - laravel

The following query works fine, but the problem is that it gives the id of the events table instead of tasks table id in the output result.
Task::join('events', function ($join) {
$join->on('events.task_id', '=', 'tasks.id')
->where('events.event_type', '=', 'Task')
->where('events.task_stage', '!=', 'assigned');
})->select('tasks.*')
->get();

Try this, one should work
->select('*', 'tasks.id as taskID')->get();
This is because maybe both tasks and events table have id field. So u need to use a separate query to specify the id.

try this one
use mysql alias here
Task::join('events', function ($join) {
$join->on('events.task_id', '=', 'tasks.id')
->where('events.event_type', '=', 'Task')
->where('events.task_stage', '!=', 'assigned');
})->select('tasks.*','tasks.id as taskId')->get();

Related

Using Laravel Query Builder, how to join tables from two different databases

I have two different tables in sql server database on the same host that I need to join together in a query.
I would like to use the laravel QueryBuilder to do so.
I've tried so far:
return DB::table('users')
->select([
'users.id',
'Resources.FirstName'
])
->join('Resources.dbo.ID', 'Resources.UserID', '=', 'users.id');
It results in the following error: General error: 1 near ".": syntax error (SQL: select "users"."id", "Resources"."FirstName" from "users" inner join "Resources"."dbo"."ID" on "Resources"."ID" = "users"."id")
If I copy the query in my dabatase script editor and run it, it runs correctly and give the expected result.
I have also tried this
return DB::table('users')
->select([
'users.id',
'Resources.FirstName'
])
->join(DB::raw('Resources.dbo.ID'), 'Resources.UserID', '=', 'users.id');
return DB::table('users')
->select([
'users.id',
'Resources.FirstName'
])
->join(DB::raw('Resources.ID'), 'Resources.UserID', '=', 'users.id');
->join('Resources', function($q) {
$q->connection('tcollect')->on('Resources.ID', '=', 'users.id');
});
Is there a way to achieve this?
Please try that
DB::table('Database1.Resources as dt1')-> join('Database2.users as dt2', 'dt2.id', '=', 'dt1.UserID')->select(['dt1.*','dt2.*'])->get();

How create a subquery with eloquent and laravel with softdeletes

I am using Laravel 7 and Vue.js 2.
I want to retrieve the tasks that are not assigned to a specific user.
I made the following code that works correctly.
$tasks_user = TaskUser::select('task_id')
->where('user_id', $id)
->get();
$tasks = Task::select('tasks.id as id', 'tasks.name as name', 'tasks.description as description')
->join('task_user', 'tasks.id', '=', 'task_user.task_id')
->whereNotIn('task_user.task_id', $tasks_user)
->distinct()
->get();
By the way to be more elegant I decided to transform the above code into a single query as follows:
$tasks = Task::select('tasks.id as id', 'tasks.name as name', 'tasks.description as description')
->join('task_user', 'tasks.id', '=', 'task_user.task_id')
->whereNotIn('task_user.task_id', function($q) use ($id)
{
$q->select('task_id')
->from('task_user')
->where('user_id', $id)
->get();
})
->distinct()
->get();
Unfortunately I discovered that the above query didn't work because it doesn't considers softdeletes.
For example, if the user with id 3 was related with the task 7 but now that row has been deleted with softdeletes in the table task_user, the first code returns also the task with id 7 (correctly) and the second one not (uncorrectly).
So finally, I must do a single query that works as the first code.
Can help?
You can actually combine both approaches. whereNotIn accepts also an Eloquent Query, it doesnt need to be a callback. Try this:
$userRelatedTasksQuery = TaskUser::select('task_id')
->where('user_id', $id);
$tasks = Task::select('tasks.id as id', 'tasks.name as name', 'tasks.description as description')
->join('task_user', 'tasks.id', '=', 'task_user.task_id')
->whereNotIn('task_user.task_id', $userRelatedTasksQuery)
->distinct()
->get();
Be sure to not use get() at the end of the $userReleatedTasksQuery, as you want the eloquent query instance, not the result.

Laravel: Use order by in combination with whereHas

I want to retrieve a collection of data, which is ordered by the start_date of the relation
Basically I want to achieve this, with Laravel Models (the code below works perfectly)
$posts = DB::table('posts')
->leftJoin(
'threads',
'posts.id',
'=',
'threads.postable_id'
)
->where('threads.postable_type', '=', 'App\Post')
->orderBy('threads.start_date')
->paginate($request->input('limit', 2));
So in this case, I'm fetching ALL Posts and those are ordered by the start_date of the thread relation.
Those are not my actual tables but this works perfectly!
Because I'm using https://laravel.com/docs/8.x/eloquent-resources this is not the ideal solution to retrieve sorted data.
So instead I want to use the orderBy clause somewhere here
$posts = Post::whereHas('thread', function ($query) {
$query->where('end_date', '>=', Carbon::now());
});
But I just cannot make this work. I've tried this
$posts = Post::whereHas('thread', function ($query) {
$query->where('end_date', '>=', Carbon::now())
->orderBy('start_date');
});
and I also appended this to the actual relation:
public function thread(): MorphOne
{
return $this->morphOne('App\Thread', 'postable')->orderBy('start_date');
}
If you look at your code:
$posts = Post::whereHas('thread', function ($query) {
$query->where('end_date', '>=', Carbon::now())
->orderBy('start_date');
});
the whereHas will only return Post associate with a thread which the function return true.
Try this:
$posts = Post::with('thread')->has('thread')->orderBy('thread.start_date')->get();
This will fetch all Post with Thread only if they have at least one Thread and then orderBy the start_date of the Thread.
You don't have to do the whereHas function because when you call ->with('thread') it'll use you this :
public function thread(): MorphOne
{
return $this->morphOne('App\Thread', 'postable')->orderBy('start_date');
}
whereHas doesnt retrieve the relationship.
If you need even more power, you may use the whereHas and orWhereHas methods to define additional query constraints on your has queries, such as inspecting the content of a comment: Laravel whereHas
Don't do :
$posts = Post::with('thread')->orderBy('thread.start_date');
If there is no thread on some post, post without thread will be fetch with value null for their key thread and you will have an unexpected result when you try to orderBy.
First of all I want to thank Elie Morin for his help but I found out that I definitely need to use joins for that task.
In my example, I wanted to order the main query (posts) by the relation's start_date
Doing what you suggested
$posts = Post::with('thread')->has('thread')->orderBy('thread.start_date')->get();
Would only order the thread by start_date and not the ENTIRE query.
Which is why I came up with something like this:
$posts = Post::has('thread')
->select('posts.id')
->leftJoin(
'thread',
'posts.id',
'=',
'thread.postable_id'
)
->where('thread.postable_type', '=', 'App\Post')
->where('thread.end_date', '>=', Carbon::now())
->orderBy('thread.start_date')
->with('thread');
return PostResource::collection($posts->paginate(2));

use of orWhere() in Eloquent

I have a eloquent query that I am running twice, but feel can be run once.
I'd want to return the values of the first where statement if exists otherwise check the second where statement which is the default in the query.
This is what I am currently doing:
$details = Telco::select('telcos.id AS telco_id', 'telcos.name AS telco_name')
->leftJoin('telco_prefixs', 'telco_prefixs.telco_id', '=', 'telcos.id')
->where('telco_prefixs.prefix', '=', $phone_number) // check if ndc exists
->first();
if ($details){
return $details;
}
return Telco::select('telcos.id AS telco_id', 'telcos.name AS telco_name')
->leftJoin('telco_prefixs', 'telco_prefixs.telco_id', '=', 'telcos.id')
->where('telcos.name', '=', 'Default') //default channel
->first();
I have a feeling this can be combined to something like below:
However, this fails as keeps executing the OrWhere clause.
Telco::select('telcos.id AS telco_id', 'telcos.name AS telco_name')
->leftJoin('telco_prefixs', 'telco_prefixs.telco_id', '=', 'telcos.id')
->where('telco_prefixs.prefix', '=', $phone_number) // if ndc exists
->Orwhere('telcos.name', '=', 'Default') //default channel
->first();
Someone help. Thanks
Try to add your where and or where condition as below.
Telco::select('telcos.id AS telco_id', 'telcos.name AS telco_name')
->leftJoin('telco_prefixs', 'telco_prefixs.telco_id', '=', 'telcos.id')
->where(function ($query) use($phone_number) {
$query->where('telco_prefixs.prefix', '=', $phone_number);
$query->Orwhere('telcos.name', '=', 'Default');
})->first();
I you want to use just eloquent a possible solution would be to have something like:
I suppose you have model called Telco and another one calle TelcoPrefix.
//Telco.php
//first we create a has many relationship with your telco_prefixs table.
public function telcoPrefixs(){
return $this->hasMany(TelcoPrefix::class);
}
Once you have that relationship you can use something similar to this code:
Telco::whereHas('telcoPrefixs',function($query, $phone_number){
return $query->where('prefix,'=',$phone_number);
})->select('id','name')->first();
This will compare the relationship and if it exists or has it will return your first record in one query.
Hope it helps at least to give a guide of what you can do.

How to select instances with multiple relations?

I have some models Featured_Course_Request, Course_Request, Response and Teacher. Featured_Course_Request hasOne Course_Request and Course_Request hasMany Response by Teacher.
I want to get the only Featured_Course_Requests on which logged in teacher has not responded (have no Response by logged in teacher.) How can I do it?
I am trying to achieve it with the following code but it is not giving correct output.
$featured_course_request = Featured_Course_Resquest::whereRaw('remaining_coins >= coins_per_click')->where('status', '=', 'open')
->whereHas('courseRequest', function($q) use ($teacher){
$q->whereHas('responses', function($qe) use ($teacher){
$qe->where('teacherID', '!=', $teacher->id);
});
});
You can target nested relations with the dot syntax: 'courseRequest.responses' further more you'll need whereDoesntHave instead of whereHas:
$featured_course_request = Featured_Course_Resquest::whereRaw('remaining_coins >= coins_per_click')
->where('status', '=', 'open')
->whereDoesntHave('courseRequest.responses', function($q) use ($teacher){
$qe->where('teacherID', '=', $teacher->id);
})
->get();

Resources