Laravel: write query to count sales with group by weeks - mysql

I have mysql database having a sales table, representing a list of products sold daily, with columns of product name, price and created_at. I could get the number of sales for a certain day by doing this for instance;
$sales = Sale::where('created_at', $certain_day')->count();
However, i need to track the sales per week for a number of weeks, say the number of products sold from the beginning of this week (sunday) till date, the number of sales last week, the number of sales two weeks ago and so on, for the last five weeks, returned as an array (something like this:[{30/12/2021: 10}, {25/12/2021: 15}, {18/12/2021: 22}]. How can i write laravel eloquent query to achieve this?

Try something like this:
$from = date('2018-01-01');
$to = date('2018-05-02');
Sale::whereBetween('created_at', [$from, $to])->get();
Then you can use Carbon method for current week, previous week, next week
Sale::whereBetween('created_at', [Carbon::now()->startOfWeek(), Carbon::now()->endOfWeek()])->get();
#update
Sale::selectRaw('*,UNIX_TIMESTAMP(created_at) DIV '.$sec. ' as group_date')->groupBy('group_date');
For week,month and day you can do
->groupBy(function($data) {
// day
return Carbon::parse($data->created_at)->format('Y-m-d');
//month
return Carbon::parse($data->created_at)->format('Y-m');
//week
return Carbon::parse($data->created_at)->format('W');
})

This following query gives you the last 5 weeks with the count of sales in each week:
SELECT FROM_DAYS(TO_DAYS(created_at) - MOD(TO_DAYS(created_at), -1, 7)) AS weeklyGrouping , COUNT(*) AS sales_count
FROM sales
GROUP BY weeklyGrouping
ORDER BY weeklyGrouping DESC
LIMIT 5
The formula above assumes that Sunday is the first day of the week and in case your weeks start on Mondays, change the -1 to -2.
for descriptive information you can refer to this article.
EDIT (Eloquent query builder Style)
$sales = Sale::selectRaw('COUNT(*) AS sales_count')
->selectRaw('FROM_DAYS(TO_DAYS(created_at) - MOD(TO_DAYS(created_at), -1, 7)) AS weeklyGrouping')
->groupBy('weeklyGrouping')
->orderBy('weeklyGrouping', 'DESC')
->take(5);

Related

Sql query mistake for the weekly statistics

I am trying to make a weekly statistics for user registration. It should work for weekly. There are total of seven days in a week. I want to print the number of users who are registered every day in the week on the screen.
For example:
Number of users who registered on Monday = 38
Number of users who registered on Tuesday = 11
.... .... and this list will only list the week we were
I created a sql query like the following:
SELECT WEEKDAY(registerTime)+1, count(*)
FROM users group by WEEKDAY(registerTime)
ORDER BY WEEKDAY(registerTime)
But the outcome of this question is very different. This total shows the number of users who registered on Monday for every year .
You want to limit users to only this week so you don't get everything:
SELECT WEEKDAY(registerTime)+1, count(*)
FROM users
WHERE WEEKOFYEAR(registerTime) = WEEKOFYEAR(CURDATE())
AND YEAR(registerTime) = YEAR(CURDATE())
group by WEEKDAY(registerTime)
ORDER BY WEEKDAY(registerTime);
Basically you match the year and week of year with what you need. That should be enough.
Try like this :
SELECT datepart(week, registerTime), count(*) FROM Users GROUP BY datepart(week, registerTime)
You can also use Php code for this purpose. First make array of days and then you can get registered users for each day through that array
function today()
{
return date("Y-m-d");
}
function last_seventh_day()
{
return date("Y-m-d",strtotime("-7 days"));
}
$days = ['Saturday','Sunday','Monday','Tuesday','Wednesday','Thursday','Friday'];//Array that stores all days
foreach($days as $day)
{
$sql = "select * FROM users where day = '$day' and date_column between " .today() . "and" .last_seventh_day() ;
}
I have updated my answer. I hope this will work for you!

Select records according to month's last day

I have table having 26 columns in which first 3 Columns are day,month,year. And rest of columns having some information that i have to show. Now i have to fetch records according to month's last day.
I have tried writing code.
select * from subscription_stats where year * 10000 + month * 100 + day = LAST_DAY(CONCAT(year,'-',month,'-',day))
But this will fetch records from last day of every month. When i dont have actual last day in records then this code will not work. So instead of LAST_DAY i want some functionality like MAX date in that month. How can i implement this functionality.
You want the last date in each month in your data. For this:
select s.*
from subscription_stats s
where s.day = (select max(s2.day)
from subscription_stats s2
where s2.year = s.year and s2.month = s.month
);
Although it would not make this query much simpler, you should be storing dates as dates in your table. That is, one date, not three separate columns for year/month/day.

mysql: slightest difference between days

i want to write a query which shows me the slightest difference between a given day of a month and the days in the tables.
select * from students where 5 = month(birthdate)
I want to search for the students who were born in May and now i want to get the slightest difference between a given day and the day of the birthday.
For example:
Alan 1980-05-03
Bob 1978-05-07
And i set the day to 8. The result should show me Bob. How should the query look like?
You could use:
SELECT *
FROM students
WHERE month(birthdate) = 5
ORDER BY ABS(DAY(NOW()) - DAY(birthdate))
LIMIT 1;
SqlFiddleDemo
When you compare only in one month range you could easily get difference between day in particular month.
Note: This won't handle ties.
Here you set the day, you choose all students with birthday that matches the birth date closest to the day you chose.
Set #Day = 5; -- your number
Select * from students
where month (birthdate)=5 -- set this to month
Having birthdate = (select min(birthdate) from students order by abs(#Day - dayofmonth(birth date)) desc limit 1);
Dayofmonth() returns the day (1-31) of the month for a given date.

MySQL: Returning records from the current month and previous 3 months

I'm using PHP/MySQL booking system and i'm using a Google Line Chart to try and display the gross sales from the current month, and also the previous 3 months.
Each booking has a date in the standard phpmyadmin "date" format, so yyyy:mm:dd.
So, im looking to get 4 results from 4 queries, each query filtering out a certain month and grabbing the sum of each booking from that month.
My question is, how can i distinguish between the months in the query? How would i structure the query?
Based on the title:
select * from bookings where MONTH(CURDATE())=MONTH(booking_date);
select * from bookings where MONTH(booking_date) > MONTH(CURDATE()-INTERVAL 3 MONTH) and < MONTH(CURDATE() + INTERVAL 1 MONTH);
For simple per-month searches you can use the following:
Select * from bookings where MONTHNAME(booking_date)='July' and YEAR(booking_date)=2013;
Or:
Select * from bookings where MONTH(booking_date)=7 and YEAR(booking_date)=2013;
Also since you've already got the months, you could do this (this method requires that you maintain a table of ending dates for each month an compensate for leap year though):
select * from bookings where booking_date>'2013-06-30' AND booking_date<'2013-08-01';
In first place, excuse my english....
I know this is old thread and cant comment but, #AbsoluteƵERØ, that answer apply to the current month, in example, if i got records of July in 2013-2014-2015, the query will return the records on the month for those years.... To avoid that and using your posted code:
SELECT * FROM bookings WHERE MONTH(CURDATE()) = MONTH(booking_date) AND YEAR(CURDATE()) = YEAR(booking_date);
Note: if use the "name form" and specify the year there's no problem, like this:
SELECT * FROM bookings WHERE MONTH(CURDATE()) = MONTH(booking_date) AND YEAR(booking_date) = 2013;

generate reports in MYSQL between 2 dates grouped by week

I have a staff timesheet table where i have timestamp of when those records are created. I now want to generate the report so that my start date is Tuesday and end date is next Monday, which is 1 week. Now i need to generate all the records grouped by this weeks time but will be next set of tuesday to monday.
This is like normal GROUP BY WEEK(Timestamp) but the WEEK numbers are not the default ones i need to generate the reports in this custom duration. I have a query working for this which groups the record efficiently by Week 1, week 2, week 3 etc.. which is picked from default mysql calendar i guess. How can i change that to generate reports grouped by custom weeks ?
Can you tel me how the following works as how the dates are picked up ?
SELECT WEEK(pw.date) AS Date,DATE_FORMAT(pw.date,'%d-%m-%Y') AS post_date,
SUM(wages) AS amount,SUM(pw.hours) AS hours,SUM(pw.minutes) AS minutes
FROM pos_sessions pw
GROUP BY YEAR(pw.date), WEEK(pw.date) ORDER BY pw.date DESC
I think this Other Solution is what you are looking for...