Laravel using Sum and Groupby - php

I would like to fetch sum of quantity in each month, so that I can display on bar chart quantities against month
This is what I thought but didn't workout
$data1 = Borrow::groupBy(function($d) {
return Carbon::parse($d->created_at)->format('m')->sum('quantity');
})->get();
My table structure
Schema::create('borrows', function (Blueprint $table) {
$table->increments('id');
$table->integer('member_id');
$table->integer('book_id');
$table->integer('quantity');
$table->integer('status')->default(0);
$table->timestamps();
});

that a collection group by not an eloquent groupby
if you want to do it with eloquent, gotta:
$data1 = Borrow::selectRaw('SUM(quantity) as qt, MONTH(created_at) as borrowMonth')
->groupBy('borrowMonth')->get();
if you want to do it with the collection groupBy method, you should first do the get, then the groupBy.
As in, though im not sure what you're trying to accomplish with what you do inside the callback..
$data1 = Borrow::get()->groupBy(function($d) {
return Carbon::parse($d->created_at)->format('m')->sum('quantity');
});

try this query , you will get month wise count :
use DB;
$month_wise_count=DB::table("borrows")
->select(DB::raw('CONCAT(MONTHNAME(created_at), "-", YEAR(created_at)) AS month_year'),
DB::raw("MONTH(created_at) as month , YEAR(created_at) as year"),
DB::raw("(COUNT(*)) as total_records"),
DB::row("(SUM('quantity') as total_value"))
->orderBy(DB::raw("MONTH(created_at),YEAR(created_at)"))
->groupBy(DB::raw("MONTH(created_at),YEAR(created_at)"))
->get();

Related

Laravel - Eloquent - How to sum related data and query agaist it?

I'm looking for help with database queries, not collection solution
I have the following models:
User
Order
Product
User hasMany orders, and orders belongsToMany products
I'm in a place where I would need to query users and select all sold products, meaning the sum of all products quantities that are attached to the orders.
quantity value is stored in the order_product pivot table.
Table name: users, orders, products & order_product
Ideally, I would like to make queries like: select all users that have sold at least 100 products, for example.
DB::raw() & selectRaw is most likely the way to go, I think(?), but I'm not sure about the syntax and how to actually make the query, with and without where clause.
Thanks a lot in advance, this has bothered me for a while
Database Schemas
Schema::create('users', function (Blueprint $table) {
$table->bigIncrements('id');
});
Schema::create('orders', function (Blueprint $table) {
$table->bigIncrements('id');
$table->unsignedBigInteger('user_id')->index();
});
Schema::create('order_product', function (Blueprint $table) {
$table->bigIncrements('id');
$table->unsignedBigInteger('order_id')->index();
$table->unsignedBigInteger('product_id')->index();
$table->integer('quantity')->unsigned()->default(1);
});
Schema::create('products', function (Blueprint $table) {
$table->bigIncrements('id');
});
UPDATE
This far I have come:
\App\User::addSelect([
'sold_products_count' => \App\Order::whereColumn('user_id', 'users.id')
->join('order_product', 'orders.id', '=', 'order_product.order_id')
->select(DB::raw('sum(order_product.quantity) as qty')),
])->where('users.sold_products_count', '>=', 100);
HOWEVER, the last statement where('users.sold_products_count', '>=', 100) throws error, cuz there's no sold_products_count column.
So I think I'm on the right track, but how I can use the new sum column in where clause?
Can I use addSelect, or do I have to use something else?
Finally, I solved this
Here's the answer:
\App\User::addSelect([
'sold_products_count' => \App\Order::whereColumn('user_id', 'users.id')
->join('order_product', 'orders.id', '=', 'order_product.order_id')
->select(DB::raw('sum(order_product.quantity) as qty')),
])->having('sold_products_count', '>=', 100);
The idea is to first count the sum via addSelect and then we can query against the value using having, neat
DB::table('users')
->join('orders', 'orders.user_id', '=', 'users.id')
->join('order_product', 'orders.id', '=', 'order_product.order_id')
->select('users.*', DB::raw('sum(order_product.quantity) as qty'))
->having('qty', '>=', 100)
->get();

Laravel eloquent build query

I want to write a query using the Laravel Eloquent structure. I want to query these values ​​after entering the min and max values. I have a product table. Column product table with discount (%) and price. I want to get min and max value according to the discounted value of the product.
I want this to be based on the query including the discount.
$products->where('price', '<=', $max)
->where('price', '>=', $min)
->orderByDesc('id')
->paginate(9);
Product migration:
Schema::create('products', function (Blueprint $table) {
$table->bigIncrements('id');
$table->unsignedBigInteger('upper_category_id')->index();
$table->unsignedBigInteger('category_id')->index();
$table->unsignedBigInteger('user_id')->index();
$table->string('name');
$table->longText('text');
$table->float('price')->index();
$table->integer('stock');
$table->float('discount');
$table->timestamps();
});
Thank you very much in advance.
If I correctly understood your question, you can try do it this way:
$products->where(DB::raw('price - price * discount'), '<=', $max)
->where(DB::raw('price - price * discount'), '>=', $min)
->orderByDesc('id')
->paginate(9);
https://laravel.com/docs/5.8/queries#raw-expressions

Optimize Laravel Eloquent whereHas() query - very slow

I am using Laravel 5.4
I have 3 models: Order, OrderLine and Product.
Order hasMany() OrderLines
OrderLine hasOne() Product via the product_id in the OrderLine model (I have properly indexed this, at least I think!)
My requirement is to retrieve all Orders and OrderLines where the Product is for a certain brand name.
Here is my eloquent query. I know the query works but it seems to infinitely run when put on a large dataset (circa 10,000 Orders, 12,000 OrderLines/Products)
$orders = Order::whereBetween('order_date', [$this->start_date,$this->end_date])
->whereHas('lines', function ($q1){
$q1->whereHas('product', function ($q2){
$q2->where('brand', 'Brands>SanDisk');
});
})->with('lines')->with('lines.product')->get()->toArray();
This produces the following SQL when debugging via toSql() method.
select
*
from `orders`
where
`order_date` between ? and ?
and
exists (select * from `order_lines` where `orders`.`id` =`order_lines`.`order_id`
and
exists (select * from `products` where `order_lines`.`product_id` = `products`.`id` and `brand` = ?))
My 3 migrations to create the tables are as follows (I have removed anything except keys for simplicity):
Schema::create('orders', function (Blueprint $table) {
$table->increments('id');
});
Schema::create('order_lines', function (Blueprint $table) {
$table->increments('id');
$table->integer('product_id');
$table->integer('order_id');
});
Schema::create('products', function (Blueprint $table) {
$table->increments('id');
});
I then added the following index:
Schema::table('order_lines', function (Blueprint $table) {
$table->integer('product_id')->unsigned()->change();
$table->foreign('product_id')->references('id')->on('products');
});
Results of EXPLAIN syntax as follows:
1 PRIMARY orders ALL 91886 Using where
2 DEPENDENT SUBQUERY order_lines ALL 93166 Using where
3 DEPENDENT SUBQUERY products eq_ref PRIMARY PRIMARY 4 mymemory_main.order_lines.product_id 1 Using where
Try this:
mpyw/eloquent-has-by-non-dependent-subquery: Convert has() and whereHas() constraints to non-dependent subqueries.
mpyw/eloquent-has-by-join: Convert has() and whereHas() constraints to join() ones for single-result relations.
$orders = Order::query()
->whereBetween('order_date', [$this->start_date, $this->end_date])
->hasByNonDependentSubquery('lines.product', null, function ($q) {
$q->where('brand', 'Brands>SanDisk');
})
->with('lines.product')
->get()
->toArray();
That's all. Happy Eloquent Life!

Laravel Sub queries in select using query builder

I want to get this query using query builder:
SELECT *,
( SELECT sum(vendor_quantity)
from inventory
WHERE product_id = products.id
) as qty from products
I'm stuck with this part
(SELECT sum(vendor_quantity) from inventory where product_id = products.id)
I can do it using raw query but I want to know if there is a way to do it in query builder.
My Table Schema for products:
Schema::create('products', function (Blueprint $table) {
$table->increments('id');
$table->string('product_type',50);
$table->string('product_name',255);
$table->string('internal_reference',255);
$table->string('barcode',255);
$table->decimal('sale_price', 10, 2);
$table->decimal('cost', 10, 2);
$table->decimal('weight', 10, 2);
$table->decimal('volume', 10, 2);
$table->integer('added_by')->unsigned();
$table->timestamps();
});
// Foreign Keys
Schema::table('products', function(Blueprint $table) {
$table->foreign('added_by')->references('id')->on('users');
});
Stocks Table:
Schema::create('stocks', function (Blueprint $table) {
$table->increments('id');
$table->integer('product_id')->unsigned();
$table->integer('vendor')->unsigned();
$table->string('vendor_product_code',255);
$table->string('vendor_product_name',255);
$table->integer('vendor_quantity');
$table->decimal('vendor_price', 10, 2);
$table->date('vendor_produce');
$table->date('vendor_expiry');
$table->integer('added_by')->unsigned();
$table->timestamps();
});
// Foreign Keys
Schema::table('stocks', function(Blueprint $table) {
$table->foreign('product_id')->references('id')->on('products');
$table->foreign('vendor')->references('id')->on('customers');
$table->foreign('added_by')->references('id')->on('users');
});
can you just add what exactly do you need as output? Like what do you plan to throw at your view so I can give you the eloquent setup. From the migration above it looks like you're missing some tables like "inventory".
In any way - you first need to setup eloquent relationships between your models. For the two above, something like this:
class Stock extends Model{
public function product(){
return $this->belongsTo(Product::class);
}
}
and
class Product extends Model{
public function stock(){
return $this->hasMany(Stock::class);
}
}
Now, that sum of yours has me confused a bit... since vendor_quantity is a column in your stocks table... Do you need to get all the products and the corresponding foreign key values from the stocks table and then sum all the values in the vendor_quantity? If that's the case do something like this:
$products = Products::with('stock')->get();
This will return the eloquent collection with all your products AND foreign key values from the stock table. Since you have the values from the related table you can just iterate through each of those an add it to a variable or just append it to the initial object for passing to your view. For example
$products = Product::with('stock')->get();
foreach ($products as $key => $product){
$vendorQuantitySum = $product->stock->sum('vendor_quantity');
$products[$key]->vendorQuantity = $vendorQuantitySum;
}
Now, when you pass $products to your view, you can easily get the sum in your view like so:
{{ $product->vendorQuantity }}
I just tested it on my Laravel install and it seems to work :)

represent my sql query in laravel Eloquent

I have an application tha i want it to make bookings but i'am having trouble making my Eloquent query
I have two modals "Booking.php" and "Room.php" my bookings migrations table is as follows
Schema::create('bookings', function(Blueprint $table)
{
$table->increments('id');
$table->string('name');
$table->integer('phone');
$table->integer('time_in');
$table->integer('room_id');
$table->integer('time_out');
$table->string('days');
$table->string('type');
$table->integer('expiry_status'); /*expiry status 0->expired 1->not expired*/
$table->timestamps();
});
and my rooms migrations table is as follows
Schema::create('rooms', function(Blueprint $table)
{
$table->increments('id');
$table->integer('room_no');
$table->integer('price');
$table->timestamps();
});
in my view i have got inputs for satrt of reservation(time_in) and end of reservation(time_out) now if there is a reservation that does not end before or start after the reservation we want, the room is considered busy therefore i do not want to show that room show those rooms for my reservation dates.
My problem is I want to know the rooms available between my reservation dates,Can someone help me to write the eloquent to get the available rooms from the above table structures. I'm using mysql as the database engine. Thanks in advance.
I found this query to be useful but how to i implement it in the form of Eloquent model
SELECT r.id
FROM rooms r
WHERE r.room_id NOT IN (
SELECT b.room_id FROM bookings b
WHERE NOT (b.time_out < '2012-09-14T18:00'
OR
b.time_in > '2012-09-21T09:00'))
ORDER BY r.room_id;
You can create subselects and advanced where conditions in Laravel Eloquent.
This script worked for me. I tried to build it for your schema.
DB::table('rooms')
->whereNotIn('room_id', function($query)
{
$query->select('room_id')
->from(with(new Booking)->getTable())
->where(function($query)
{
$query->where('time_out', '<', '2012-09-14T18:00')
->orWhere('time_in', '>', '2012-09-21T09:00');
});
})
->orderBy('room_id')
->get();
https://gist.github.com/DengoPHP/d3e95441a7b9e27299b7

Categories