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');
Related
How can I order a result set by something on its relationship?
I am trying to get the Eloquent equivalent of this:
SELECT * FROM users INNER JOIN roles ON users.role_id = roles.id ORDER BY roles.label DESC
Here is what I am trying (based on the documentation):
$order = 'desc';
$users = User::with(['role' => function ($q) use ($order) {
$q->orderBy('label', $order);
}])->paginate(10);
but it doesn't order them properly. What am I doing wrong?
EDIT: Not sure if showing the model relationship is relevant but here it is:
public function role()
{
return $this->belongsTo(Role::class);
}
You should do it with join
User::with('role')->join('role', 'role.id', '=', 'users.id')->orderBy('role.label', $order)->paginate(10);
I have 3 tables : Orders ( id, name, surname, created_at and updated_at ), OrdersStatuses (order_id, order_status_name_id, created_at) and OrderStautsNames ( id and name ):
I have orders model which has method like this:
protected $appends = ['actual_status'];
public function orderProducts()
{
return $this->hasMany(OrderProduct::class);
}
public function statuses()
{
return $this->belongsToMany(OrderStatusName::class, 'order_statuses')
->withPivot('created_at');
}
public function getActualStatusAttribute()
{
return $this->statuses()->latest('set_at')->first();
}
I have problem with seraching all orders, where highest status id ( this info is in pivot table OrderStatuses, and I need name of this status which is in OrderStatusNames ) is like $statuses (this is an array with statuses ). I started do like this:
$orders = Order::query();
$orders->whereHas('statuses', function($query) use ($statuses) {
$query->whereIn('order_status_name_id', $statuses);
});
But it return me orders with not latest status, but this query search me throught all statuses... . Can i do this by latest status? I tryed to use current_status but I don't know how to get there.
Add this relation to your Order Model
public function lastStatus()
{
return $this->hasOne(OrderStatusName::class)->select('OrderStautsNames.*', 'order_statuses.order_id', DB::raw('MAX(order_statuses.set_at) as lastOrder'))->join('order_statuses', 'order_statuses.order_status_name_id', '=', 'OrderStautsNames.id')
}
Then eager load it
$orders = Order::whereHas('lastStatus', function ($query) use ($statuses) {
$query->whereIn('OrderStautsNames.id', $statuses);
})->get();
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();
I have places and locations tables.
Place could have many locations. Location belongs to Place.
Place:
id
title
Location:
id
place_id
floor
lat
lon
class Location extends Model {
public function place()
{
return $this->belongsTo('App\Place');
}
}
And
class Place extends Model {
public function locations()
{
return $this->hasMany('App\Location');
}
}
And i need to find places, that belongs only to 1st floor. select * from places inner join locations on places.id = locations.place_id where locations.floor = 1
How does it should be done in Eloquent?
Is something similar to
Place::where('locations.floor', '=', 1)->get() exists?
Yes, i know there is whereHas:
Place::whereHas('locations', function($q)
{
$q->where('floor', '=', 1);
})->get()
but it generates a bit complex query with counts:
select * from `places` where (select count(*) from `locations` where `locations`.`place_id` = `places`.`id` and `floor` = '1') >= 1
does not this works?
class Location extends Model {
public function place()
{
return $this->belongsTo('App\Place');
}
}
$locations = Location::where('floor', '=', 1);
$locations->load('place'); //lazy eager loading to reduce queries number
$locations->each(function($location){
$place = $location->place
//this will run for each found location
});
finally, any orm is not for database usage optimization, and it is not worth to expect nice sql's produced by it.
I haven't tried this, but you have eager loading and you can have a condition:
$places = Place::with(['locations' => function($query)
{
$query->where('floor', '=', 1);
}])->get();
Source
Try this :
Place::join('locations', 'places.id', '=', 'locations.place_id')
->where('locations.floor', 1)
->select('places.*')
->get();
I have 3 tables:
products
|id|name|about|
=categories=
|id|name|parent|
=products-categories=
|id|product_id|cat_id|
I need to take a product categories names. I have a sql query:
SELECT s.name FROM products AS p
LEFT JOIN `products-categories` AS cats ON p.id = cats.product_id
LEFT JOIN `categories` AS s ON cats.cat_id = s.id
WHERE product_id = 1;
And It works! But how I can do this with the help of Laravel Eloquent (Not Fluent!)
You can use Eloquent relationship and in this case, create two models, for both tables, i.e. product and Category:
class Category extends Eloquent {
protected $table = 'categories'; // optional
public function products()
{
return $this->belongsToMany('Product', 'products_categories', 'category_id', 'product_id');
}
}
class Product extends Eloquent {
protected $table = 'products'; // optional
public function categories()
{
return $this->belongsToMany('Category', 'products_categories', 'product_id', 'category_id');
}
}
Now you may use these relationship methods to get related data, for example:
$product = Product::with('categories')->find(1);
This will return the product with id 1 and all the related categories in a collection so you may use $product->categories->first()->name or you may do a loop on the categories like:
foreach($product->categories as $cat) {
echo $cat->name;
}
Also you may use join which doesn't require the relationship methods and you may use same approach to join the models that is used in Fluent (Check other answer). But either way, you need to store the category and product mappings in the products_categories table. Read more about many-to-many relationship on Laravel website.
Just use the leftJoin method. It works the same in Eloquent as in Query Builder.
$product = Product::leftJoin('product-categories', 'product-categories.product_id', '=', 'products.id')
->leftJoin('categories', 'categories.id', '=', 'product-categories.cat_id')
->where('product_id', 1)
->first(['categories.name']);