How can I implement SUM() in Laravel relations? - php

Here is my query which works as well:
SELECT sum(r.rating) as rank,b.* FROM books as b
LEFT JOIN ranks as r ON b.id = r.book_id
WHERE 1
GROUP BY (b.id)
ORDER BY rank DESC
Now I want to do the same in Laravel. Here is what I've tried:
// Book model
class Book extends Model
{
public function ranks()
{
return $this->hasMany(Rank::class)->sum("rating");
}
}
// Controller
$obj = new Book;
$get = $obj->ranks()->orderBy('rating', 'desc')->get();
It throws this error:
Call to a member function groupBy() on integer
Any idea how can I fix this problem?

public function ranks() {
return $this->hasMany(Rank::class)
->select('book_id', \DB::raw('sum(`rating`) as `rank`'))
->groupBy('book_id');
}
$books = Book::with('ranks')->get();
$sortedBooks = $books->sortByDesc(function($book) {
return $book->ranks->sum('rank');
});

Related

Multiple Joins in Eloquent from local scopes

Got a question regarding Eloquent and the scope functionality:
Assuming two scopes:
class Result extends Model {
public function scopeIsRace($query) {
return $query
->join('sessions', 'sessions.id', '=', 'results.session_id')
->where('sessions.type', 10)
}
public function scopeIsOfficial($query) {
return $query
->join('sessions', 'sessions.id', '=', 'results.session_id')
->join('events', 'events.id', '=', 'sessions.event_id')
->where('events.regular_event', 1);
}
}
Calling both of them performs two joins of sessions and the resulting query looks sth like this (doesnt work)
select * from `results` inner join `sessions` on `sessions`.`id` = `results`.`session_id` inner join `sessions` on `sessions`.`id` = `results`.`session_id` inner join `events` on `events`.`id` = `sessions`.`event_id` where `driver_id` = 24 and (`sessions`.`type` = 10 or `sessions`.`type` = 11) and `events`.`regular_event` = 1
How do I prevent the double join on sessions?
Thank you so much #Nima. Totally forget about an advanced whereHas. Used a structure llke this from your suggested question and it works perfectly fine:
public function scopeIsRace($query) {
return $query->whereHas('session', function($query){
$query->where('type', 10);
});
}
public function scopeIsOfficial($query) {
return $query->whereHas('session', function($query) {
return $query->whereHas('event', function($query2) {
$query2->where('regular_event', 1);
});
});
}

Issue with group by laravel and sql

Firstly I have problem which count products which are sold every day. In sql I have query
select product_name, sum(quantity) as quantity from invoice_product
join invoices on invoices.id = invoice_product.invoice_id
join products on products.id = invoice_product.product_id
where invoices.issued_at = '2019-05-16'
and products.`made_by_us` = 1
group by product_name
It show me interesting for me information but I used product_name to make group by but I should use product_id - I need show name too but I don't know how to do it.
Secondly I want to use it in Laravel so maybe someone know which is it possible to do it in Eloquent?
Thank you in advance :)
I would go with withCount() combined with select(DB::raw()), like this:
$products = Product::withCount(['invoices as quantity' => function ($query) {
$query->select(DB::raw('sum(quantity)'));
}])->get();
Then, you can access each quantity sum like this:
$quantity = $products->first()->quantity;
You would need to update your model relationships to achieve that.
Models:
InvoiceProduct Model
class InvoiceProduct extends Model
{
protected $table = 'invoice_product';
protected $guarded = [
'id',
];
}
public function invoice()
{
return $this->belongsTo('App\Invoice'); // Assuming `Invoice` Model is directly in app folder
}
public function product()
{
return $this->belongsTo('App\Product'); // Assuming `Product` Model is directly in app folder
}
Controller:
$full_query = InvoiceProduct::whereHas('invoice', function ($query) {
return $query->where('issued_at', '2019-05-16');
})->whereHas('product', function ($query) {
return $query->where('made_by_us', 1);
});
$product_names = $full_query->get(['product_name']);
$total_quantities = $full_query->sum('quantity');

i get this error: Object of class Illuminate\Database\Eloquent\Builder could not be converted to string in laravel ORM

I get this error:
Object of class Illuminate\Database\Eloquent\Builder could not be converted to string
when I run this code:
public function index()
{
save_resource_url();
//$items = News::with(['category', 'photos'])->get();
$items = Solicitud::rightjoin(News::with(['category', 'photos']),'news.id','=','solicitud.event_id')->count('*','event_id','as','total')->get();
return $this->view('news_events.index', compact('items'));
}
my original sql query
SELECT *,count(event_id) as total FROM solicitud RIGHT JOIN news ON news.id = solicitud.event_id group by title;
The error you are getting is because you are putting the Builder as first parameter News::with(['category', 'photos']). it should only be the string(table name) like 'news'.
Click here to read more
So the query should
$items = Solicitud::rightjoin( 'news','news.id','=','solicitud.event_id')->count('*','event_id','as','total')->get();
Solve:
my original code
public function index()
{
save_resource_url();
$items = News::with(['category', 'photos'])->get();
return $this->view('news_events.index', compact('items'));
}
change my sql query:
SELECT *,count(event_id) as total FROM solicitud RIGHT JOIN news ON news.id = solicitud.event_id group by title;
this query produced duplicate columns
for this:
select news.*,count(event_id) as total from news left join solicitud on solicitud.event_id = news.id group by news.id;
this query shows only the columns of the users table plus the 'total' table in relation to the 'request' table
in my code transform to eloquent
public function index()
{
save_resource_url();
$items = News::with(['category', 'photos'])->leftjoin('solicitud','solicitud.event_id','=','news.id')->groupBy('news.id')->select('news.*',DB::raw('count(event_id) as total'))->get();
return $this->view('news_events.index', compact('items'));
}

Sorting by joined data Yii2

In my Yii2 project I have post and post_views tables, and a Post model.
There are 2 fields in post_views:
post_id
views_counter
I'm using PostSearch and PostsQuery (ActiveQuery) for my queries.
My Task is: I need to get all my posts with custom field views where I get views_counter from post_views.
I'm not using hasMany in model because there is no model for post_views table in the project and I'd prefer not to create it if possible. Also, I need to sort my posts by views field. I'm stuck on this:
public function topPosts(){
$junction_table = '{{%post_views}}';
return $this->innerJoin($junction_table, Post::tableName().'.id='.$junction_table.'.post_id');
}
The main problem is that I don't know how to join and return data properly.
I need this query:
SELECT p.*, pv.views_count FROM posts p INNER JOIN post_views pv ON p.id = pv.post_id ORDER BY pv.views_count DESC;
First, you need to update your Post model with viewCount field:
class Post extends \yii\db\ActiveRecord
{
private $viewCount;
public static function tableName()
{
return "posts";
}
public function setViewCount($viewCount)
{
$this->viewCount = $viewCount;
}
public function getViewCount()
{
return $this->viewCount;
}
}
Then you need to include viewCount field in select list like this:
$post = new Post();
$query = $post->find()
->alias('p')
->select(['p.*', 'pv.views_count viewCount'])
->innerJoin("post_views pv", "p.Id = pv.id")
->limit(100)
->orderBy(["pv.views_count" => SORT_DESC]);
//Get SQL query string
echo $query->createCommand()->getSql();
//Execute query
$result = $query->all();

Delete with join in codeigniter

function delete_ScormByIdPlataforma($id_platform)
{
$query = $this->db->query("delete from scormvars where scoinstanceid in
(select scoinstanceid from dispatch where id_licencia in
(select id_licencia from licencias where id_plataforma = $id_platform))");
// return true;
}
This is my function in my model, the query is ok, but I don't know how to execute the query.
You load the model class, then call the function:
$this->load->model('my_class');
$this->my_class->delete_ScormByIdPlataforma($id_platform);
Replacing my_class with the name of the class.

Categories