laravel eloquent query group by last id - laravel

Hi I'm trying to get the last register in DB for each equipment
I got like
id | id_equip
-----+----------
1 | 3
2 | 3
3 | 3
4 | 2
5 | 2
I want to query like the last id of each equip like:
id | id_equip
-----+----------
3 | 3
5 | 2
I tried this:
$calibracao = $this->calibracao->orderBy('id', 'DESC')->groupBy('id_equip')->get();
thanks for the help!

A simple way, without join, using max:
$query = DB::table('equip')
->select(DB::raw('*, max(id) as id'))
->groupBy('id_equip')
->orderBy('id', 'asc')
->get();
(Assuming, of course, that you can count on your id to be in date order.)
You can also do this with Eloquent, using a self-referencing one-to-one relationship. The query takes longer, but it's much more Laravel-like:
Define the relationship in your model:
class myModel extends Eloquent {
public function latestEquipment()
{
return $this->hasOne('myModel', 'id_equip', 'id_equip')->latest();
}
}
(Note that in this case, we're using latest() so that we don't rely on the order of ids to determine the most recent entry, but rather on the created_at date of each record. This is more accurate.)
To retrieve all the records, with their latest equipment entry:
$latest = myModel::with('latestEquipment')->groupBy('id_equip')->get();
// loop over the results
foreach ($latest as $l) {
if ($l->equipment) {
echo('ID: ' . $l->id . 'ID_EQUIP: ' . $l->id->id_equip . '<br>');
}
}

I'm not sure if there's an easier way and this is kind of convoluted because of the join, but it should give the result you want:
DB::table('equip as e')
->select('e.*')
->join(DB::raw("(SELECT id_equip, MAX(id) id FROM equip GROUP BY id_equip) as _e"), function ($join) {
$join->on('e.id', '=', '_e.id')->on('e.id_equip', '=', '_e.id_equip');
})
->orderBy('id', 'asc')
->get();

public function latest($equipamentos)
{
foreach ($equipamentos as $equip)
{
$latest[$equip->cod] = DB::table('tb_calibracao')
->where('cod_equipamento', $equip->cod)
->where('parecer', '1')
->orderBy('cod', 'Desc')
->first();
}
return $latest;
}
That worked, thx for the help!

Related

How to add a momentary value to a sql query in Laravel

I have this query in Laravel 8:
$articles = Article::whereIn('category_id', $categories)->where(function ($query) {
$query->where(function ($query2) {
$query2->where('draft', 0)->whereNull('publication_date');
})->orWhere(function ($query2) {
$query2->where('draft', 0)->where('publication_date', '<=', DateHelper::currentDateTime());
});
})->orderBy('publicated_at', 'DESC')->get();
I need to add a momentary id to this query named desc_id, so that the values $articles that i query have a desc_id based on the publication_date.
The result that i need to achieve is like this:
id
name
category
publication_date
desc_id
3
bananas
news
2022-01-16 17:30:00
1
27
kiwis
news
2021-12-05 21:30:00
3
50
apples
news
2022-01-07 09:14:00
2
I've tried adding it by passing all the elements of $articles into an empty array adding a value:
$count =0;
$allArticles = [];
foreach ($articles as $article) {
$count++;
$allArticles[] = $article->with('desc_id', $count);
}
I know that my method is incorrect but i hope that it helps understanding my question.
It looks like you want to have the line number of each row which can be achieve like this :
Article::whereIn(...)->select()
->addSelect(DB::raw('RANK() OVER(ORDER BY publicated_at DESC) as desc_id'))
->orderBy('publicated_at', 'DESC')
->get();

Order by relationship with pagination laravel eloquent

I have the relationship below, an application belongs to a user.
Users table
ID | Name
1 | Danny
2 | Mark
Applications table
ID | user_id
1 | 1
2 | 2
Application.php
public function user()
{
return $this->belongsTo(User::class);
}
I'm trying to sort the application by user's name and paginate the result. I tried the code below, the pagination is working but the order by doesn't have any effect.
$query = Application::query();
$query = $query->with(['user' => function ($query){
$query->orderBy('name', 'DESC');
}]);
$query = $query->paginate(10);
Try using inner join and order by relation column:
$applications = Application::select('*')
->join('authors', 'applications.user_id', '=', 'users.id')
->orderBy('authors.name', 'DESC')
->paginate(10);
Try this:
Application::join('users', 'applications.user_id', '=', 'users.id')
->orderBy('users.name','desc')
->with('users')
->get();

laravel Eloquent query WhereHas wrong result

I have two tables and relations as bellow
user
the user table:
id
name
active
1
abc
1
2
xyz
Null
3
abx
0
the book table:
id
user_id
name
active
1
1
book1
0
2
2
book2
0
3
1
book3
0
relation is as this
user->books (HasMany)
return $this->hasMany(Book::class,'user_id','id');
my query is as bellow
User::with('book')
->WhereHas('book', function($query) {
$query->where(['active'=> 1]);
})
->where(['id'=> 1,'active'=>1])
->get();
This query is getting zero records because active is 0 in books
But i want to see all user record and if there is matching record with active 1 in book.
second is query user for active 1 or Null and for that if use ->orwhereNull('active')
All records changes.
Thanks
I guess you need to apply filter on related records (with()) instead of applying filter on whole query. So this way you will always get a list of users along with the list of active books only
User::with(['book'=> function($query) {
$query->where('active', 1);
}])
->where(function ($query) {
$query->where('active', 1)
->orWhereNull('active');
})
->get();
I have used logical grouping here so in case if you have more filter clauses to add in your query.
Or you can define a new relation in your user model to pick only active related books as
class User extends Model
{
public function book()
{
return $this->hasMany(Book::class, 'user_id', 'id');
}
public function active_books()
{
return $this->hasMany(Book::class, 'user_id', 'id')
->where('active', '=', 1);
}
}
User::with('active_books')
->where(function ($query) {
$query->where('active', 1)
->orWhereNull('active');
})
->get();
You have id and active column on both table, so I think you need to change your query like this :
User::with('book')
->WhereHas('book', function($query) {
$query->where(['books.active'=> 1]); // books table active column
})
->where(['id'=> 1,'active'=> 1]) // users table id, active column
->get();

How to get post which have multiple table relationship?

my database scheema
Table POST
| id | title | content |
Table SharedGroup
|id | title | slug
Table Post_SharedGroup
|id| post_id | shared_group_id|
i want to make a query in laravel that i give slug of sharedgroup and get post of it
$data = Post::whereHas('sharedGroup',function($query) use($slug){
$query->whereIn('slug',$slug);
})->get();
where $slug is your slug array given by you
Model Post
public function sharedGroup(){
return $this->belongsToMany('App\SharedGroup');
}
Model SharedGroup
public function post(){
return $this->belongsToMany('App\Post');
}
You seem to just want a basic join between the three tables:
$posts = DB::table('POST p')
->join('Post_SharedGroup ps', 'p.id', '=', 'ps.post_id')
->join('SharedGroup s', 'ps.shared_group_id', '=', 's.id')
->whereIn('s.slug', array(1, 2, 3)) // match slug values (1, 2, 3)
->select('p.*')
->get();

Laravel "whereHas" with "take"

I'm having a relationship:
employees: id | name
employments: id | employee_id | company_id | start_date | end_date | termination_type_id
One employee can have many employments through time. I need to get employees who are employed based on the last/one row in employments and that is whereHas fails me. I've set this in my model Employee.php:
In Employee.php model:
public function latestEmployment() {
return $this->hasMany(Employment::class)->orderBy('start_date', 'DESC')->take(1);
}
On filtering:
$employees->where(function ($query) {
$query->whereHas('latestEmployment', function($subquery) {
$subquery->whereNull('termination_type_id');
}
});
Looks to me that I need somewhere some eager loading because ->take(1) doesn't work that way. Here whereHas takes into account the whole table, no matter what I write next.
Thanks for help.
EDIT:
Doing first(), get(), etc. executes the query in the middle so I cannot use that. Important thing is that the whole query needs to be a Builder because I need a paginate() at the end.
The easiest solution is getting all employees and filtering them afterwards:
public function latestEmployment() {
return $this->hasOne(Employment::class)->orderBy('start_date', 'DESC');
}
Employee::with('latestEmployment')->get()
->where('latestEmployment.termination_type_id', null);
A query that only fetches the relevant employees:
Employee::select('employees.*')
->join('employments', 'employees.id', 'employments.employee_id')
->whereNull('termination_type_id')
->where('start_date', function($query) {
$query->selectRaw('max(start_date)')
->from('employments')
->whereColumn('employee_id', 'employees.id');
})->get();
Try Something like this
Employee::select('employees.*')->join('employments', function ($join) {
$join->on('employees.id', '=', 'employments.employee_id')
->whereNull('emails.termination_type_id');
})->distinct()->paginate(15);

Resources