Laravel Eloquent, group by month/year - php

i'm trying to group my data by month and year.
$data ->select(DB::raw('count(id) as `data`'),DB::raw('YEAR(created_at) year, MONTH(created_at) month'))
->groupby('year','month')
->get();
The output is :
{
"data": 19215,
"year": 2016,
"month": 10
},
if i group only by month, i don't know from which year belong this month, my expected output is :
{
"clicks": 19215,
"month": 11-2016,
},
{
"clicks": 11215,
"month": 12-2016,
},
i want to do it in sql, not in php.

You can try as:
->select(DB::raw('count(id) as `data`'), DB::raw("DATE_FORMAT(created_at, '%m-%Y') new_date"), DB::raw('YEAR(created_at) year, MONTH(created_at) month'))
->groupby('year','month')
->get();

Note: This is solution based on eloquent, and yes, it not the best approach, but as the question is, this is using eloquent. If you want faster way, you can do it with raw query.
If you want to group your results for example by year, you can use closure where you will parse your datetime to desired format (year or month).
Here is example of the code:
$res= ModelName::where('someColumn','test')
->get()
->groupBy(function($val) {
return Carbon::parse($val->created_at)->format('Y');
});

$result = ModelName::selectRaw('year(created_at) year, monthname(created_at) month, count(*) data')
->groupBy('year', 'month')
->orderBy('year', 'desc')
->get();

for latest version of mysql, the accepted answer will give error, so instead try
$data
->selectRaw("
count(id) AS data,
DATE_FORMAT(created_at, '%Y-%m') AS new_date,
YEAR(created_at) AS year,
MONTH(created_at) AS month
")
->groupBy('new_date')
->get();
ref: https://dev.mysql.com/doc/refman/8.0/en/date-and-time-functions.html#function_date-format

The answer by #Amit Gupta is a good, but it isn't working >= MySQL 5.7/MariaDB 10.2 and calls the error:
Syntax error or access violation: 1055 Expression #2 of SELECT list is not in GROUP BY clause and contains nonaggregated column
To solve that issue, you can use eg. MIN() on the nonaggregated column:
->select(
DB::raw("
count(id) as data,
MIN(DATE_FORMAT(created_at, '%m-%Y')) as new_date,
YEAR(created_at) year,
MONTH(created_at) month
")
)
->groupBy('year', 'month')
->get();

$data ->select(DB::raw('count(id) as `data`'),DB::raw('YEAR(created_at) year'),DB::raw('MONTH(created_at) month'))
->groupBy(DB::raw('YEAR(created_at)'), DB::raw('MONTH(created_at)'))
->get();

=>this might help someone in 2019
$date = "2019-06-16";
return date('m', strtotime($date)); //this return you 06(edited)
so you can do foreach by this method , so you don't need to do the all sql things..

Related

yii2 query date field with other field

I have a table:
id,
name,
date,
warning_days
I'm trying to query the table like this:
$result= Table::find()->where([
'<=', 'date', date('Y-m-d', strtotime('+ '.'warning_days'.' days'))])->all();
I'm fiddling with the code, but can't seem to find a way...
Can somebody, point me in the right direction?
Thanks in advance, regards, Rui
the simplest way is the use of where method in literal format based on date_add( )
$result= Table::find()
->where( 'date <= date_add( date, INTERVAL warning_day DAY)')
->all();
or you can use operator format
$result= Table::find()
->where( ['<= ', date , 'date_add( date, INTERVAL warning_day DAY)'])
->all();

Return data ordered by date

I have a function that returns the count of sales each day. The problem with this approach is that I want the data to be stored by date but I am getting them in the following order:
01-Dec
02-Dec
03-Dec
03-Nov
04-Nov
05-Nov
etc.
I understand why that happens but I am not sure how to solve it. I can replace subMonth(1) with startofmonth which woul partially solve my problem but this is not what I want. I instead want to return the last 30 days ordered.
return DB::table('sales')
->select(\DB::RAW('DATE_FORMAT(created_at, "%d-%M") as date'), \DB::raw('COUNT(*) as count'))
->where('created_at', '>=', Carbon::now()->subMonth(1))
->orderBy('date')
->groupBy('date')
->get(['date', 'count'])
->keyBy('date')
->transform(function ($data) {
return $data->count;
});
I also tried orderBy('created_at') but it gives me the error below and I'd like to avoid changing the sql mode.
Syntax error or access violation: 1055 Expression #3 of SELECT list is not in GROUP BY clause and contains nonaggregated column 'x.sales.created_at' which is not functionally dependent on columns in GROUP BY clause; this is incompatible with sql_mode=only_full_group_by
EDIT:
As requested, this the sql query of the return statement
select DATE_FORMAT(created_at, "%d-%M") as date, COUNT(*) as count from `sales` where `created_at` >= ? group by `date` order by `date` asc
i don't have much idea about your framework query syntax. but you can take one more column DATE_FORMAT(created_at, "%Y%m%d") AS order_column and apply order, and group by on column "order_column" and use column "data" while display data.
select DATE_FORMAT(created_at, "%Y%m%d") AS order_column, DATE_FORMAT(created_at, "%d-%M") as date, COUNT(*) as count from `sales` where `created_at` >= ? group by `order_column` order by `order_column` asc
return DB::table('sales')
->select(\DB::RAW('DATE_FORMAT(created_at, "%Y%m%d") AS order_column'),\DB::RAW('DATE_FORMAT(created_at, "%d-%M") as date'), \DB::raw('COUNT(*) as count'))
->where('created_at', '>=', Carbon::now()->subMonth(1))
->orderBy('order_column')
->groupBy('order_column')
->get(['date', 'count'])
->keyBy('date')
->transform(function ($data) {
return $data->count;
});
If you make this in 2 steps does it work?
Step1 in which you create date column:
$step1 = DB::table('sales') ->select(\DB::RAW('DATE_FORMAT(created_at, "%d-%M") as date')))
->where('created_at', '>=', Carbon::now()->subMonth(1))
->orderBy('date')
->get(['date', 'count'])
and after that you make the agregation:
$step2 = $step1->select('date'), \DB::raw('COUNT(date) as count'))
->groupBy('date') ->get(['date', 'count']) ->keyBy('date')
Hope it helps!

Laravel 5.4 Query Builder SUM() from two different tables

I'm having problems getting the SUM of a certain field from two tables.
So to start things off, here's my query.
//Getting of Cost of Goods Sold (Menus)
$totalMenuCost = DB::raw('(SUM(orders.qty * orders.cost)) as cost');
$yearMenuSold = DB::raw('YEAR(orders.created_at) as year');
$menuscost = DB::table('orders')
->where('status', 'served')
->select($totalMenuCost, $yearMenuSold);
//Getting of Cost of Goods Sold (Items)
$totalItemCost = DB::raw('(SUM(purchases.qty * purchases.cost)) as cost');
$yearItemSold = DB::raw('YEAR(purchases.created_at) as year');
$itemcost = DB::table('purchases')
->where('status', 'served')
->union($menuscost)
->select($totalItemCost, $yearItemSold)
->get();
And when I try to do return $itemcost. It returns two rows:
[
{
cost: "792.00",
year: 2017
},
{
cost: "1700.00",
year: 2017
}
]
I'm trying to make it return a single row but having it added, like this:
[
{
cost: "2492.00", // that's 1,700 + 792
year: 2017
}
]
$itemcost = DB::table('purchases')
->where('status', 'served')
->union($menuscost)
->select($totalItemCost, $yearItemSold)
->get();
In your Example you are just selecting $totalItemCost, $yearItemSold and union from other table ($menuscost).
So that won't add up the results.
///////////Try Changing your Query in this Format
select column1,sum(column2) total
from
(
select column1,column2
from Table1
union all
select column1,column2
from Table2
) t
group by column1
Hope this Helps..
Let me know if more help is needed.
All seems okay, Have you changed your $itemcost like this
$itemcost = DB::table('purchases')
->where('status', 'served')
->select($totalItemCost, $yearItemSold)
->union($menuscost)
->groupBy('year')
->get();
UPDATE
Since above not working for your case,
I think problem on group by is with union so Have a new try with this one.
$menuscost = DB::table('orders')
->where('status', 'served')
->select($totalMenuCost, $yearMenuSold)
->groupBy('year');
$itemcost = DB::table('purchases')
->where('status', 'served')
->select($totalItemCost, $yearItemSold)
->groupBy('year')
->union($menuscost)
->groupBy('year')
->get();
If this is not working then can you add output of this query.

Laravel 5.4 - Stats by month

I would like to count all the users who have the state "visible" and "ghost" like this :
public function getStatsUser() {
$data = self::whereIn('state', array('Visible', 'Ghost'))
->count();
return $data;
}
But i would like to have these data each month from the first user, like this :
['Month', 'Data'],
['December 2016', 4000],
['January 2017', 4600],
['February 2017', 11020],
['March 2017', 5400]
And for the date i have a row with "created_at" but not a specific row for the month.
I tried this, but it's not working
$data= self::select(DB::raw('count(*) as monthly_total'), DB::raw('MONTH(created_at) as month'))
->whereIn('state', array('visible', 'Ghost'))
->whereYear('created_at', '=', date('Y'))
->groupBy('month')
->count();
The error :
SQLSTATE[42S22]: Column not found: 1054 Champ 'month' inconnu dans group statement (SQL: select count(*) as aggregate from `oiseau` where `etat_actuel` in (Relaché, En convalescence) and year(`date_signalement`) = 2017 group by `month`)
Thanks for your help !
This should get you started:
self::selectRaw('CONCAT_WS(" ", MONTHNAME(created_at), YEAR(created_at)) as date, COUNT(*) as count')
->whereIn('state', array('visible', 'Ghost'))
->groupBy(DB::raw('YEAR(created_at)', MONTH(created_at)))
->get()
The query will return a Collection of objects with a date and a count.
Probably the most important part is to group by both the year and the month and you can use functions there instead of raw columns.
PS: This will get you Laravel Models from the self class, which they really aren't... so maybe replace the self with DB::table('users') or similar.
You can try like:
$data = self::whereIn('state', array('Visible', 'Ghost'))
->select(DB::raw('count(*) as monthly_total') , DB::raw('MONTH(created_at) month'))
->groupBy('month ')
->get();
Or try Join Query if Month is stored in other Table.

Using datediff from 2 joined tables

I'd like to get the difference between two dates on two tables. The uploads.published_at compared to the completed_guides.created_at
I keep getting an error which says:
SQLSTATE[42000]: Syntax error or access violation: 1582 Incorrect parameter count in the call to native function 'datediff' (SQL: select users.*,completed_guides.created_at as completed_at,uploads.published_at,datediff(HOUR, published_at, completed_at) from `users` inner join `uploads` on `users`.`id` = `uploads`.`user_id` inner join `completed_guides` on `uploads`.`id` = `completed_guides`.`upload_id` where `completed_guides`.`upload_id` = 2839 limit 10)
Here is my code. Any help would be appreciated.
$select = [
'users.*',
'completed_guides.created_at as completed_at',
'uploads.published_at',
'datediff(HOUR, published_at, completed_at) as date_diff'
];
return User::select(DB::raw(join(',', $select)))
->join('uploads', 'users.id', '=', 'uploads.user_id')
->join('completed_guides', 'uploads.id', '=', 'completed_guides.upload_id')
->where('completed_guides.upload_id', $this->id)
->take(10)
->get();
You can use Laravel Query Builder's whereRaw() like this:
return User::select(DB::raw(join(',', $select)))
->join('uploads', 'users.id', '=', 'uploads.user_id')
->join('completed_guides', 'uploads.id', '=', 'completed_guides.upload_id')
->where('completed_guides.upload_id', $this->id)
->whereRaw('datediff(uploads.published_at, completed_guides.completed_at) as date_diff')
->take(10)
->get();
To set the format of date you can use SQL method - date_format(date, format) like this:
->select(DB::raw("DATE_FORMAT(date_diff, '%b %d %Y %h:%i %p') as formatted_date_diff"));
See more about SQL Date Format
Hope this helps!
The one with units, is timestampdiff, not datediff.
timestampdiff(HOUR, published_at, completed_at) as date_diff

Categories