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.
Related
Good Evening.... Hope i can explain my problem correctly.
I am getting data (ID) in array and value (numbers) in controller. Now i want to save the "numbers" in each "ID".
array ID ["Buffalo-01", "Buffalo-02", "Buffalo-04"]
Numbers - 40.
Want to save 40 to each ID.
Controller
public function addbuffalototalmilk(Request $req )
{
$buffalomilking = Buffalodata::where('avgmilk','<>','0')->Where('status','=','Available')->count(); // MIlking Animal Nos
$getbuffalomilkingid = Buffalodata::where('avgmilk','<>','0')->Where('status','=','Available')->pluck('buffaloID'); // Get Buffalo Details of Milking
$totalmorningmilk = $req->get('morningtotalmilk');
$totaleveningmilk = $req->get('eveningtotalmilk');
$eachmorningmilk = ($totalmorningmilk / $buffalomilking);
$eacheveningmilk = ($totaleveningmilk / $buffalomilking);
return response ();
}
Thanks in Advance
Is this what you are looking for ?
$buffalomilking = Buffalodata::where('avgmilk', '<>', '0')
->Where('status', '=', 'Available')
->count();
$getbuffalomilkingid = Buffalodata::where('avgmilk', '<>', '0')
->Where('status', '=', 'Available')
->pluck('buffaloID');
foreach ($getbuffalomilkingid as $id) {
Buffalodata::where('id', $id)->update([
'number' => $buffalomilking,
]);
}
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'));
}
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);
Let's say I have two models: Park and Items. Each Park can have a number of Items, through a HasMany relationship.
In Items table there's a park_id field and a type flag: an Item can be a fountain, or a basketball court, or whatever.
What I need to do is to filter the parks to obtain only those who has ALL of the item types passed in an array. This is what I have:
$parks = Park::whereHas('items', function($q) use ($request) {
$q->where('type', json_decode($request->type_list));
})->get();
But it's not working properly. Any ideas?
Thanks a lot, and happy new year to all!
Edit: I've found a working though really ugly solution:
$types_array = json_decode($request->type_list, true);
$results = [];
// A collection of parks for each item type
foreach($types_array as $type) {
$results[] = Park::whereHas('items', function($q) use ($type) {
$q->where('type', $type);
})->get();
}
// Intersect all collections
$parks = $results[0];
array_shift($results);
foreach ($results as $collection) {
$parks = $collection->intersect($parks);
}
return $parks;
You can use a foreach in whereHas method. It should be something like this:
$array = json_decode($request->type_list, true)
$parks = Park::whereHas('items', function($q) use ($array) {
foreach ($array as $key => $type) {
$q->where('type', $type);
}
})->get();
I think using where clause to match all item's type for the same row will result nothing, it's like doing where id = 1 and id = 2 and this is impossible because id can take only one value, what you should do is to use whereIn to get all items that match at least one type and then use groupBy to group result by park_id, then in the having clause you can check if the group count equal the type_list count:
$types = json_decode($request->type_list, true);
$parks = Park::whereHas('items', function($q) use ($types) {
$q->select('park_id', DB::raw('COUNT(park_id)'))
->whereIn('type', $types)
->groupBy('park_id')
->havingRaw('COUNT(park_id) = ?', [ count($types) ]);
})->get();
You can add multiple whereHas() constraint to one query:
$types_array = json_decode($request->type_list, true);
$query = Park::query();
foreach($types_array as $type) {
$query->whereHas('items', function($q) use($type) {
$q->where('type', $type);
});
}
$parks = $query->get();
I have a model tasks with complete tasks with datetime in the past and upcoming tasks with datetime in the future.
While retrieving the tasks, I want to display the upcoming tasks arranged in ascending order (from now to the future) and tasks in the past in descending order (from now to the past).
public function getTasks()
{
$futureTasks = Task::whereDate('datetime', '>', Carbon::now())->orderBy('datetime', 'asc')->get();
$pastTasks = Task::whereDate('datetime', '<', Carbon::now())->orderBy('datetime', 'desc')->get();
$tasks = array_merge($futureTasks, $pastTasks);
$response = ['tasks' => $tasks];
// return...
}
I'm getting the following error:
array_merge(): Argument #1 is not an array
If I reverse the order of arguments for array_push function, I still get the same error.
public function getTasks()
{
$futureTasks = Task::whereDate('datetime', '>', Carbon::now())->orderBy('datetime', 'asc')->get();
$pastTasks = Task::whereDate('datetime', '<', Carbon::now())->orderBy('datetime', 'desc')->get();
$tasks = array_merge($pastTasks, $futureTasks);
$response = ['tasks' => $tasks];
// return...
}
And If I retrieve only the futureTasks or pastTasks without array_merge, I get the desired output.
public function getTasks()
{
$futureTasks = Task::whereDate('datetime', '>', Carbon::now())->orderBy('datetime', 'asc')->get();
$response = ['tasks' => $futureTasks];
// return...
}
What am I doing wrong here? Thanks a lot for your time.
Both the results are a collection. You can use the collection merge method.
public function getTasks()
{
$futureTasks = Task::whereDate('datetime', '>', Carbon::now())
->orderBy('datetime', 'asc')
->get();
$pastTasks = Task::whereDate('datetime', '<', Carbon::now())
->orderBy('datetime', 'desc')
->get();
$tasks = $futureTasks->merge($pastTasks);
$response = compact('tasks');
// return...
}
Since you're using the whereDate condition, you're missing all the data from the present date based on your queries. You might want to check that.