Laravel groupBy date get total column - laravel

I want to report before the selected date and the entered day. Dates that are not before the selected date and the number of days are also coming. I don't want empty dates to appear and I want to show the total column data in the database for that date. Where am I doing wrong?
I want to make a comparison between incoming values to change the table background-color
Database Structure
Table Structure
public function listByDaily(Request $request)
{
$endDate = $request->date('date') ?? today();
$startDate = $endDate
->copy()
->subDays($numberofdays);
$dates = CarbonPeriod::create($startDate, $endDate);
$transactions = Transactions::whereBetween('date', [$startDate, $endDate])
->select('product_id', 'supplier_id', 'total', 'date')
->latest('date')
->get();
$productIds = $transactions
->pluck('product_id')
->unique()
->values()
->toArray();
$supplierIds = $transactions
->pluck('supplier_id')
->unique()
->values()
->toArray();
$productselect = Product::whereIn('id', $productIds)
->select('id', 'product_name')
->pluck('product_name', 'id');
$suppliers = Supplier::whereIn('id', $supplierIds)
->select('id', 'supplier_name')
->get();
$columns = collect($transactions)
->whereNotNull('date')
->groupBy('date','DESC')
->map(function($items) {
return $items
->groupBy('product_id','total');
})
->pluck('total');
//dd($columns);
/*->toArray();*/
$products = Transactions::join('products', 'products.id', '=', 'transaction.product_id')->get()->unique();
return view('transactions.reportbydates', compact('products', 'productIds', 'dates', 'suppliers', 'columns'));
}

Related

Laravel query groubBy condition

I have a dB query where I would like to groupBy() only when conditions are met without using union because of pagination.
Unfortunately groupBy() seems to only work when called on the entire query outside of the loop.
This was made for dynamic filtering from $filterArr. Depending on the array I need to select from different columns of the table.
When the $key=='pattern' I would need the distinct results from its column.
the query looks something like this
select `col_1`, `col_2`, `col_3`
from `mytable`
where (`color` LIKE ? or `pattern` LIKE ? or `style` LIKE ?)
group by `col_2` //<< i need this only for 'pattern' above and not the entire query
Heres the model:
// $filterArr example
// Array ( [color] => grey [pattern] => stripe )
$query = DB::table('mytable');
$query = $query->select(array('col_1', 'col_2', 'col_3'), DB::raw('count(*) as total'));
$query = $query->where(function($query) use ($filterArr){
$ii = 0;
foreach ($filterArr as $key => $value) {
if ($key=='color'){
$column = 'color';
}else if ($key=='style'){
$column = 'style';
}else if ($key=='pattern'){
$column = 'pattern';
$query = $query->groupBy('col_2'); // << !! does not work
}
if($ii==0){
$query = $query->where($column, 'LIKE', '%'.$value.'%');
}
else{
$query = $query->orWhere($column, 'LIKE', '%'.$value.'%');
}
$ii++;
}
});
$query = $query->orderBy('col_2', 'asc')->simplePaginate(30);
I think you can simplify your code a bit:
$query = DB::table('mytable');
$query = $query->select(array('col_1', 'col_2', 'col_3'), DB::raw('count(*) as total'));
$query = $query->where(
collect($filterArr)
->only(['color','style','pattern'])
->map(function ($value, $key) {
return [ $key, 'like', '%'.$value.'%', 'OR' ];
})->all()
)->when(array_key_exists('pattern', $filterArr), function ($query) {
return $query->groupBy('col_2');
});
$query = $query->orderBy('col_2', 'asc')->simplePaginate(30);

Laravel: Sum daily (groupby date) then retain date with empty rows

stackoverflow,
I have working laravel function which get the daily sum of sales for the last 30 days.
I will use the data to build a graph, so I need to get the dates even if its empty and give them a value of "0" as their sum.
here's my code (it's working but only returns dates which are not empty)
public function getDaily() {
$startDate = Carbon::now()->subDays(30);
$endDate = Carbon::now();
$all_dates = array();
for($i = 0;$i<=30;$i++)
{
$all_dates[] = $startDate->toDateString();
$startDate->addDay();
$sales=DB::table('sale_details')
->select(DB::raw('sum(amount_due) as daily'),DB::raw('date(created_at) as date'))
->groupBy('date')
->orderBy('date','desc')
->get();
}
return $sales;
}
To get array of objects you may use good Collection's methods:
$sales = DB::table('sale_details')
->whereBetween('created_at', [$startDate, $endDate])
->select([
DB::raw('sum(amount_due) as daily'),
DB::raw('date(created_at) as date'),
])
->groupBy('date')
->get()
->keyBy('date');
$period = new CarbonPeriod($startDate, '1 day', $endDate);
// Fill zeroes
foreach ($period as $date) {
$dateString = $date->toDateString();
if (!$sales->has($dateString)) {
$sales->put($dateString, ['date' => $dateString, 'daily' => 0]);
}
}
// Convert to associative array
$sales = $sales->values()->toArray();
Try this:
$sales = DB::table('sale_details')
->whereBetween('created_at', [$startDate, $endDate])
->select([
DB::raw('sum(amount_due) as daily'),
DB::raw('date(created_at) as date'),
])
->groupBy('date')
->orderBy('date','desc')
->pluck('daily', 'date')
->toArray();
$period = new CarbonPeriod($startDate, '1 day', $endDate);
// Fill zeroes
foreach ($period as $date) {
if (!isset($sales[$date->toDateString()])) {
$sales[$date->toDateString()] = 0;
}
}
Another solution is using database-generated series of dates (pgsql example: Generating time series between two dates in PostgreSQL) and join it with result.

Pull data based on related table

I have a tables:
events[id, 'name', 'date'],
tickets ['id', event_id', 'isAvailable'],
order_tickets ['order_id', 'ticket_id'],
orders['id', 'buyer_id', 'status'].
I need to receive all orders with tickets on the events, where date >= today (do not include tickets to past events.).
My query is next:
$userId = 1;
$orders = Order::with([
'tickets',
'tickets.event',
])->where('buyer_id', $userId)
->where('status', 'sold')
->get();
You can use the whereHas() method and the today() helper function to achieve this:
$orders = Order::with('tickets.event')
->whereHas('tickets.event', function ($query) {
$query->whereDate('date', '>=', today());
})
->where('buyer_id', $userId)
->where('status', 'sold')
->get();

Filters in laravel5.4

In case I have filter users with location and date,I have written query like below
public function searchConsultants()
{
$location = $request->get('location');
$fromDate = $request->get('from_date');
$toDate = $request->get('to_date');
$data = DB::table('consultants')
->selectRaw('AVG(COALESCE(ratings.rating_for_manager, 0))as avg_rating, consultants.id,consultants.cunsultant_name,contact_number,location')
->where('location','LIKE','%'.$location.'%')
->whereBetween('date',[$fromDate,$toDate])
->leftJoin('ratings', 'ratings.consultant_id', 'consultants.id')
->groupBy('consultants.id')
->orderBy('avg_rating', 'DESC')
->get();
}
With above query I can get data but sometimes I dont want to search with date I want search only with location,
The problem in above query I must enter location and date to filter users,So How can I filter with only location or date.
Use orWhere read it at https://laravel.com/docs/5.4/queries#where-clauses
public function searchConsultants()
{
$location = $request->get('location');
$fromDate = $request->get('from_date');
$toDate = $request->get('to_date');
$data = DB::table('consultants')
->selectRaw('AVG(COALESCE(ratings.rating_for_manager, 0))as avg_rating, consultants.id,consultants.cunsultant_name,contact_number,location')
->where('location','LIKE','%'.$location.'%')
->orwhereBetween('date',[$fromDate,$toDate])
->leftJoin('ratings', 'ratings.consultant_id', 'consultants.id')
->groupBy('consultants.id')
->orderBy('avg_rating', 'DESC')
->get();
}
You should try this:
public function searchConsultants()
{
$location = $request->get('location');
$fromDate = $request->get('from_date');
$toDate = $request->get('to_date');
$data = DB::table('consultants')
->selectRaw('AVG(COALESCE(ratings.rating_for_manager, 0))as avg_rating, consultants.id,consultants.cunsultant_name,contact_number,location')
->whereBetween('date',[$fromDate,$toDate])
->orWhere('location','LIKE','%'.$location.'%')
->leftJoin('ratings', 'ratings.consultant_id', 'consultants.id')
->groupBy('consultants.id')
->orderBy('avg_rating', 'DESC')
->get();
}

Laravel how do I get the row number of an object using Eloquent?

I'd like to know the position of a user based on its creation date. How do I do that using Eloquent?
I'd like to be able to do something like this:
User::getRowNumber($user_obj);
I suppose you want MySQL solution, so you can do this:
DB::statement(DB::raw('set #row:=0'));
User::selectRaw('*, #row:=#row+1 as row')->get();
// returns all users with ordinal 'row'
So you could implement something like this:
public function scopeWithRowNumber($query, $column = 'created_at', $order = 'asc')
{
DB::statement(DB::raw('set #row=0'));
$sub = static::selectRaw('*, #row:=#row+1 as row')
->orderBy($column, $order)->toSql();
$query->remember(1)->from(DB::raw("({$sub}) as sub"));
}
public function getRowNumber($column = 'created_at', $order = 'asc')
{
$order = ($order == 'asc') ? 'asc' : 'desc';
$key = "userRow.{$this->id}.{$column}.{$order}";
if (Cache::get($key)) return Cache::get($key);
$row = $this->withRowNumber($column, $order)
->where($column, '<=',$this->$column)
->whereId($this->id)->pluck('row');
Cache::put($key, $row);
return $row;
}
This needs to select all the rows from the table till the one you are looking for is found, then selects only that particular row number.
It will let you do this:
$user = User::find(15);
$user->getRowNumber(); // as default ordered by created_at ascending
$user->getRowNumber('username'); // check order for another column
$user->getRowNumber('updated_at', 'desc'); // different combination of column and order
// and utilizing the scope:
User::withRowNumber()->take(20)->get(); // returns collection with additional property 'row' for each user
As this scope requires raw statement setting #row to 0 everytime, we use caching for 1 minute to avoid unnecessary queries.
$query = \DB::table(\DB::raw('Products, (SELECT #row := 0) r'));
$query = $query->select(
\DB::raw('#row := #row + 1 AS SrNo'),
'ProductID',
'ProductName',
'Description',
\DB::raw('IFNULL(ProductImage,"") AS ProductImage')
);
// where clauses
if(...){
$query = $query->where('ProductID', ...));
}
// orderby clauses
// ...
// $query = $query->orderBy('..','DESC');
// count clause
$TotalRecordCount = $query->count();
$results = $query
->take(...)
->skip(...)
->get();
I believe you could use Raw Expresssions to achieve this:
$users = DB::table('users')
->select(DB::raw('ROW_NUMBER() OVER(ORDER BY ID DESC) AS Row, status'))
->where('status', '<>', 1)
->groupBy('status')
->get();
However, looking trough the source code looks like you could achieve the same when using SQLServer and offset. The sources indicates that if you something like the following:
$users = DB::table('users')->skip(10)->take(5)->get();
The generated SQL query will include the row_number over statement.
[For Postgres]
In your model
public function scopeWithRowNumber($query, $column = 'id', $order = 'asc'){
$sub = static::selectRaw('*, row_number() OVER () as row_number')
->orderBy($column, $order)
->toSql();
$query->from(DB::raw("({$sub}) as sub"));
}
In your controller
$user = User::withRowNumber()->get();

Resources