How to do a cumulative count using Raw SQl / Laravel - Eloquent ORM - mysql

This is more of a SQL question than a Laravel one.
I'd like to accomplish something like the following based on my User model with the created_at field. (table users in database)
created_at
user_id
2022-04-30
1
2022-05-02
2
2022-05-03
4
date
created_users_to_this_date
total_users_created_to_date
2022-04
1
1
2022-05
2
3
Any idea on how to do so ?
What I have done so far (using Eloquent ORM) :
User::query()
->selectRaw("COUNT(*) created_users_to_this_date, DATE_FORMAT(created_at, '%Y-%m') date")
->orderBy('date')
->groupBy('date')
->get();
Equivalent SQL request
select COUNT(*) created_users_to_this_date, DATE_FORMAT(created_at, '%Y-%m') date from `users` where `users`.`deleted_at` is null group by `date` order by `date` asc
Thus returning
date
created_users_to_this_date
2022-04
1
2022-05
2
I thank you for your help

If your mysql version support window function, you can try to use SUM window function to do cumulative count
DB::table(DB::raw('(select COUNT(*) created_users_to_this_date, DATE_FORMAT(created_at, \'%Y-%m\') date
from `users`
where `users`.`deleted_at` is null
group by `date`) t1'))
->select('created_users_to_this_date','date',DB::raw('SUM(created_users_to_this_date) OVER(ORDER BY date) total_users_created_to_date'))
->get();

your equivalent sql will be
SELECT DATE ,
#running_number:=#running_number+created_users_to_this_date AS created_users_to_this_date
FROM (SELECT
COUNT(*) AS created_users_to_this_date,
DATE_FORMAT(created_at, '%Y-%m') DATE
FROM
users
where users.deleted_at is null
GROUP BY `date`
ORDER BY `date` ASC ) final
JOIN (SELECT #running_number:=0) rn

User::query()
->select('
DB::raw('COUNT(DATE_FORMAT(created_at, \'%Y-%m\') = DATE_FORMAT(now(), \'%Y-%m\')) as created_users_to_this_date'),
DB::raw('COUNT(DATE_FORMAT(created_at, \'%Y-%m\') <= DATE_FORMAT(now(), \'%Y-%m\')) as total_users_created_to_date'),
DB::raw('DATE_FORMAT(created_at, '%Y-%m') as date')
')->orderBy('date')->groupBy('date')->get();

Related

MySQL Full Group by

Since my web-host has updated the MySQL server version, my old SQL Query is not working anymore:
select COUNT(ID) AS Anzahl,
DAY(STR_TO_DATE(created_at, '%Y-%m-%d')) AS Datum
from `leads`
where `created_at` >= 2018-02-01
and `created_at` <= 2018-02-15
and `shopID` = 20
group by DAY(created_at)
order by DAY(created_at) asc
That means, I have to create a full group by query. I already have read this article but I don't really get it.
I should name all columns which are unique
Thats what I don't get. If I want to count the ID, I cannot create a group by ID query because in this case my count would always be 1. Could anybody please explain to me how full group by works and how my statement would like with a full group by statement?
Just use the same expression in the select as in the group by:
select COUNT(ID) AS Anzahl, DAY(created_at) AS Datum
from `leads` l
where `created_at` >= '2018-02-01' and
`created_at` <= '2018-02-15' and
`shopID` = 20
group by DAY(created_at)
order by DAY(created_at) asc;
You also need single quotes around the date constants.
Your select and group by columns doesn't match. You should make them same. Try below query:
select COUNT(ID) AS Anzahl,
DAY(STR_TO_DATE(created_at, '%Y-%m-%d')) AS Datum
from `leads`
where `created_at` >= 2018-02-01
and `created_at` <= 2018-02-15
and `shopID` = 20
group by Datum
order by Datum asc

Need help in executing SQL query

Here are two queries with results, I need to run one query to get same result.
1-Total slots
2-created Date
3-start date
4-end date
5-Unused Slots
First Query:-
SELECT COUNT( id ) as total_slots ,
created_date, MIN( DATE ) as start_date ,
MAX( DATE ) as end_date
FROM slots
GROUP BY created_date;
Query 1(Result)
Here is image with query result
Can I get unused slots in same query as I am getting from below query?
But here
SELECT COUNT( id ) AS unused
FROM slots
WHERE user_id =0
AND created_date = '2016-10-01 20:20:20'
Result Query with created date 2016-10-01 20:20:20
unused
79
SELECT COUNT( id ) AS unused
FROM slots
WHERE user_id =0
AND created_date = '2016-10-01 20:24:45'
Result Query with created date 2016-10-01 20:24:45
unused
51
Try
SELECT
COUNT( id ) as total_slots,
created_date,
MIN( DATE ) as start_date,
MAX( DATE ) as end_date,
COUNT(CASE WHEN user_id = 0 THEN 1 END) as unused_slots
FROM slots
GROUP BY created_date;

conversion mysql to postgresql

I have a working mysql query, but I can not get it work with postgres. This is the query (I already changed date format to to_char
SELECT country as grouper, date(users.created_at) as date,
to_char(users.created_at, '%Y-%m') as date_group,
count(id) as total_count
FROM "users"
WHERE (users.created_at >= '2011-12-01')
AND (users.created_at <= '2014-02-11')
GROUP BY grouper, date_group
ORDER BY date ASC
I am getting the error:
PG::Error: ERROR: column "users.created_at" must appear in the GROUP BY clause or be used in an aggregate function
LINE 1: SELECT country as grouper, date(users.created_at) as date, t...
Thank for your help.
SELECT country as grouper, date(MIN(users.created_at)) as date,
to_char(MIN(users.created_at), '%Y-%m') as date_group,
count(id) as total_count
FROM "users"
HAVING (users.created_at >= '2011-12-01')
AND (users.created_at <= '2014-02-11')
GROUP BY grouper, date_group
ORDER BY date ASC
MySQL is not very strict. In standard conform SQL all column values have to use an aggrate function (SUM, COUNT, MAX, MIN) on non-grouping fields - when using GROUP BY.
Honestly said, I am not entirely sure about data_group in the GROUP BY; can it be dropped?
Also note that I have switched WHERE with a HAVING.
You should use every selected column in GROUP BY section.
SELECT country as grouper, to_char(created_at, '%Y-%u') as date_group, count(id) as total_count
FROM "users"
WHERE created_at >= '2013-10-01'
AND created_at <= '2014-02-11'
GROUP BY grouper, date_group
ORDER BY date_group ASC

mysql Select from Select

I have this query:
SELECT DATE( a.created_at ) AS order_date, count( * ) as cnt_order
FROM `sales_order_item` AS a
WHERE MONTH( a.created_at ) = MONTH( now())-1
GROUP BY order_date
which will return result something like this (snapshot only otherwise will return per 31 days):
order_date cnt_order
2012-08-29 580
2012-08-30 839
2012-08-31 1075
and my full query is selecting based on above selection:
SELECT order_date
, MAX(cnt_order) AS highest_order
FROM (
SELECT DATE (a.created_at) AS order_date
, count(*) AS cnt_order
FROM `sales_order_item` AS a
WHERE MONTH(a.created_at) = MONTH(now()) - 1
GROUP BY order_date
) AS tmax
But it result :
order_date highest_order
2012-08-01 1075
Which has the date wrong and always pick the first row of date where it suppose 2012-08-31. Maybe this is a simple error that I dont know. So how to get the date right point to 2012-08-31? Any help would be great.
You could try ordering the sub query result set; something like:
SELECT
DATE (a.created_at) AS order_date,
COUNT(*) AS cnt_order
FROM
`sales_order_item` AS a
WHERE
MONTH(a.created_at) = MONTH(now()) - 1
GROUP BY
order_date
ORDER BY
cnt_order DESC
You can add ORDER BY order_date DESC in subquery.

How to group by date regardless of time?

I'm trying to group by Date(). I've got 3 records with the created_at column:
2011-12-03 08:00:24, 2011-12-03 08:12:10, 2011-12-04 09:00:00
I'd like to only group by year, month and day, regardless of time. So for the example above. It should only return two rows:
2011-12-03 and 2011-12-04
How should I go about this?
... group by date(date_time_column)
This should allow you to group by year month and day
SELECT group_by_column
, DATE_FORMAT(created_at, '%Y')
, DATE_FORMAT(created_at, '%m')
, DATE_FORMAT(created_at, '%d')
FROM my_table
GROUP BY group_by_column
or if you want to do them all together.
SELECT group_by_column
, DATE_FORMAT(created_at, '%Y%m%d')
FROM my_table
GROUP BY group_by_column
Did you try the following?
SELECT
DATE(created_at) AS created_date
FROM
my_table
GROUP BY
created_date
MySQL permits GROUP BY DATE(created_at). So that would translate in ActiveRecord to .group(DATE(created_at))
In fact, that exact example is available in the Rails Guides on ActiveRecord querying.
You can use the Date() function.
http://dev.mysql.com/doc/refman/5.1/en/date-and-time-functions.html#function_date
mysql> SELECT DATE('2003-12-31 01:02:03');
-> '2003-12-31'
TRY
GROUP BY DATE(`date_column`)
Reference