Cumulative count for each ID - mysql

Data:
Create table completion(user integer, count integer, completed date);
Insert into completion values (100,1,'2021-01-01'),(100,4,'2021-01-02'),(100,2,'2021-01-03'),
(101,4,'2021-01-05'),(101,5,'2021-01-08'),(102,1,'2021-01-04');
I want to produce 2 tables.
The 1st target is to get a cumulative count with respect to date for each individual ID:
user| cumulative | date
100| 1 | 2021-01-01
100| 5 | 2021-01-02
100| 7 | 2021-01-03
101| 4 | 2021-01-05
101| 9 | 2021-01-08
102| 1 | 2021-01-04
The 2nd target is to transform the date into number of days, counted from the minimum date for that ID:
user| cumulative | days passed
100| 1 | 0
100| 5 | 1
100| 7 | 2
101| 4 | 0
101| 9 | 3
102| 1 | 0
Thanks.

You can use window functions:
select c.*,
sum(count) over (partition by user order by completed) as cumulative,
datediff(completed, min(completed) over (partition by user)) as days_passed
from completion c;
Here is a db<>fiddle.

Related

MySQL query SELECT multiple date brackets from table

Consider the following 2 MySQL tables:
Table - Commission
id
employee_id
from_date
to_date
orders_from
orders_to
commission
1
1
2021-05-01
2021-05-05
1
10
1
2
1
2021-05-06
2021-05-10
1
10
1
3
1
2021-05-11
2021-05-15
1
10
1
4
1
2021-05-01
2021-05-05
11
20
2
5
1
2021-05-06
2021-05-10
11
20
2
6
1
2021-05-11
2021-05-15
11
20
2
7
1
2021-05-01
2021-05-05
21
30
3
8
1
2021-05-06
2021-05-10
21
30
3
9
1
2021-05-11
2021-05-15
21
30
3
Table - Orders
id
employee_id
order_date
price
An employee will get a commission based on the number of his orders during each date bracket in the "commission" table.
So for example for the first 10(1-10) orders from May 1st till May 5th he'll get 1% for each order and then for the next 10(11-20) he'll get 2% for each of those and so on.
I'm going to have a form where the manager will be able to select 2 dates from a calendar in order to see what the employee should be paid.
I want to create a MySQL query that will give me all the date brackets from the table "commission" that include the 2 dates the manager has selected?
So lets say that we select the following period:
from 2021-05-03 to 2021-05-09
How will I get all just the rows for those dates? Which in this case would be ids:1,2,4,5,7,8.
P.S. Data and use case presented here are simplified for better readability/understanding
EDIT
After Thomas G's comment
Lets say that employee with id 1 has the following orders
| id | employee_id | order_date | price |
| :--- | :---------- | :--------- | :---- |
| 1 | 1 | 2021-05-03 | 100 |
| 2 | 1 | 2021-05-07 | 100 |
| 3 | 1 | 2021-05-13 | 100 |
Now I want to check what to pay that employee for the period 2021-05-03 - 2021-05-09.
In that period only the orders 1 and 2 are applicable to be paid.
If we check the commission table we can see that for this period we need records 1 and 2.
How can get rows 1 and 2 from the commission table, using the 2 dates provided, 2021-05-03 and 2021-05-09?

mySQL how to select some data in the same field from limit date

I got the data from my table with the query
SELECT dt, place
FROM horseri
WHERE horseid = 'C299'
AND dt < '20200715'
ORDER BY dt DESC
as below, where dt is the date and the place is the winning place
dt | place
----------------------
2020-07-12 | 8
2020-06-07 | 2
2020-05-17 | 3
2020-04-12 | 9
2020-03-29 | 12
2020-03-01 | 3
2020-02-16 | 4
2020-01-27 | 5
2019-12-18 | 3
2019-11-23 | 10
2019-10-30 | 2
2019-10-01 | 9
2019-09-08 | 2
2019-07-14 | 7
2019-07-01 | 13
2019-06-16 | 7
2019-05-18 | 8
2019-03-31 | 13
2019-03-17 | 12
How can I get the first 3 winning places from the data only by the last 10 date ?
My expected output will be
dt | place
----------------------
2020-06-07 | 2
2020-05-17 | 3
2020-03-01 | 3
2019-12-18 | 3
Use a subquery to get the most recent 10 dates. Then select the top 3 places from that.
SELECT dt, place
FROM (
SELECT dt, place
FROM horseri
where horseid = 'C299'
ORDER BY dt DESC
LIMIT 10
) as x
WHERE place <= 3
The more modern way of writing Barmar's answer (assuming it be what the OP wants here), would be to use ROW_NUMBER:
SELECT dt, place
FROM
(
SELECT *, ROW_NUMBER() OVER (ORDER BY dt DESC) rn
FROM horseri
WHERE horseid = 'C299'
) t
WHERE rn <= 10 AND place <= 3;
To isolate individual places, just change the outer WHERE clause. For example, for second place finishers in the most recent 10 dates, use:
WHERE rn <= 10 AND place = 2

mysql getting average of client per day in a month

SELECT COUNT(client_ID) / DAY(LAST_DAY(dateRequested))
FROM `tbl_client`
WHERE dateRequested BETWEEN DATE_FORMAT(dateRequested,'%Y-%m-01') AND LAST_DAY(dateRequested)
I want to show the average of client per day in the month
client_ID | dateRequested
1 | 2018-07-04
2 | 2018-07-05
3 | 2018-07-06
4 | 2018-07-07
5 | 2018-08-04
6 | 2018-08-06
7 | 2018-08-09
i want to show
Average | Month
4 | July 2018
3 | August 2018
Try below query:
SELECT COUNT(client_ID),concat(month(dateRequested),year(dateRequested))
FROM `tbl_client`
WHERE dateRequested BETWEEN DATE_FORMAT(dateRequested,'%Y-%m-01') AND LAST_DAY(dateRequested)
group by concat(month(dateRequested),year(dateRequested))

Group by date every 10 days

I have this scheme:
+----+--+--------+--------------------+
| ID | Amount | paydate |
+----+-----------+--------------------+
| 1 | 200 |2016-11-05 |
+----+-----------+--------------------+
| 2 | 3000 |2016-11-10 |
+----+-----------+--------------------+
| 3 | 2500 |2016-11-11 |
+----+-----------+--------------------+
| ID | 100 |2016-11-21 |
+----+-----------+--------------------+
| 1 | 200 |2016-11-22 |
+----+-----------+--------------------+
| 2 | 3000 |2016-11-23 |
+----+-----------+--------------------+
| 3 | 2500 |2016-11-29 |
+----+-----------+--------------------+
How can I get the total Amount grouped by every 10 days like from the first of every month to the 10th then from 11th to 20th and from 21st to the end of the month?
to be shown like this :
+-----------+------------------------+
| Amount | paydate |
+-----------+------------------------+
| 3200 |2016-11-1 to 2016-11-10 |
+-----------+------------------------+
| 2500 |2016-11-11 to 2016-11-20|
+-----------+------------------------+
| 5800 |2016-11-21 to 2016-11-31|
+-----------+------------------------+
I tried
SELECT
SUM(Amount) AS Amount,
year(Facture.paydate) AS Annee,
month(Facture.paydate) AS Mois
FROM Facture
GROUP BY year(Facture.paydate), month(serFacture.paydate)
but this does not give me the result I need.
select sum(Amount) as sum_amount
,case
when day(paydate) <= 10 then concat(DATE_FORMAT(paydate,'%Y-%m-01'),' to ',DATE_FORMAT(paydate,'%Y-%m-10'))
when day(paydate) <= 20 then concat(DATE_FORMAT(paydate,'%Y-%m-11'),' to ',DATE_FORMAT(paydate,'%Y-%m-20'))
else concat(DATE_FORMAT(paydate,'%Y-%m-21'),' to ',DATE_FORMAT(paydate,'%Y-%m-31'))
end as paydate_period
from t
group by paydate_period
;
sum_amount paydate_period
3200 2016-11-01 to 2016-11-10
2500 2016-11-11 to 2016-11-20
5800 2016-11-21 to 2016-11-31
Here is an example query:
select
case
when day(date_field) between 1 and 10 then "01 to 10"
when day(date_field) between 11 and 20 then "11 to 20"
when day(date_field) between 21 and 31 then "21 to 31"
end as the_range,
date_format(date_field, "%m%Y") as the_month,
count(*)
from
the_table
group by
the_range, the_month
order by
the_month, the_range;
You can adapt the query so you display your result the way you need.

Mysql - Rows within hourly ranges on specific days using DAYOFWEEK

I am trying to get a query that will return a result set with reading total within certain hour ranges (defined in the working_hours table) depending on the DAYOFTHEWEEK for the date with a result that looks like:
working | nonworking | weekend | date | group_id
-----------------------------------------------------------------
50.3 | 30.8 | 0 | 2015-04-01 00:00 | 7
40.3 | 60.8 | 0 | 2015-04-01 00:00 | 8
50.3 | 30.8 | 0 | 2015-04-02 00:00 | 7
40.3 | 60.8 | 0 | 2015-04-02 00:00 | 8
Working and Weekend ranges are stored in the database in working_hours, Nonworking time ranges are implied (NOT BETWEEN the other ranges on that day basically)
The tables are as following:
Readings table has the hourly readings, named readings
group_id | reading | datestamp
------------------------------------------------------
7 | 30.8 | 2015-04-01 00:00
7 | 20.2 | 2015-04-01 01:00
7 | 11.2 | 2015-04-02 00:00
7 | 20.2 | 2015-04-02 01:00
8 | 26.2 | 2015-04-01 00:00
8 | 30.2 | 2015-04-01 01:00
8 | 26.2 | 2015-04-02 00:00
8 | 30.2 | 2015-04-02 01:00
Hour Ranges are stored in the working_hours table, the day column is DAYOFTHEWEEK format (1 = Sunday, 2 = Monday, etc):
group_id | day | range_start | range_end | range_type_id | day_type_id
------------------------------------------------------------------------------
7 | 5 | 08:00:00 | 15:59:00 | 1 | 1
7 | 6 | 00:00:00 | 05:59:00 | 1 | 2
7 | 6 | 06:00:00 | 23:59:00 | 2 | 2
7 | 1 | 00:00:00 | 22:59:00 | 2 | 4
7 | 1 | 23:00:00 | 23:59:00 | 1 | 4
Day Types are in the working_hours_day_type table and where things get complicated for me, Weekday and Weekend only have one range but Start/End Weekend have two ranges ('Start Weekend' first range is working hours, second range weekend hours and 'End Weekend' first range is weekend hours, second range working hours).
id | type
------------------
1 | Weekday
2 | Start Weekend
3 | Weekend
4 | End Weekend
Range Types are in the working_hours_range_type table:
id | type
------------------
1 | Working
2 | Weekend
My Mysql knowledge is limited to simple SELECT, INSERT etc and the basics of JOINs - I have found out about HOUR(datestamp) BETWEEN 8 AND 14 but dont know how to get subqueries to iterate within a parent query using WHERE datestamp BETWEEN '2015-04-01 00:00:00' AND '2015-04-02 23:59:00' if in fact thats how its done...
I am not totally clear on what constitutes working hours or non-working hours, but does this work?
SELECT
sum(CASE WHEN rtype.range_type_id = 1 THEN reading ELSE 0 END) AS working
sum(CASE WHEN rtype.range_type_id = 2 THEN reading ELSE 0 END) AS nonworking
CASE WHEN r1.daynum in (7,1) THEN 1 ELSE 0 END as weekend
date(datestamp) as date
r1.group_id
FROM
(SELECT
group_id,
reading,
time(datestamp) as rTime,
case when weekday(datestamp) = 0 THEN 2 #weekday() monday to working hours monday
when weekday(datestamp) = 1 THEN 3
when weekday(datestamp) = 2 THEN 4
when weekday(datestamp) = 3 THEN 5
when weekday(datestamp) = 4 THEN 6
when weekday(datestamp) = 5 THEN 7
when weekday(datestamp) = 6 THEN 1
else NULL
END CASE AS daynum
FROM readings) AS r1
LEFT JOIN working_hours w1
ON (r1.daynum = w1.day)
AND (r1.group_id = w1.group_id)
AND (r1.rTime BETWEEN w1.range_start AND w1.range_end)
LEFT JOIN working_hours_day_type dtype
ON w1.day_type_id = dtype.id
LEFT JOIN working_hours_range_type rtype
ON w1.range_type_id = rtype.id
GROUP BY
CASE WHEN daynum in (7,1) THEN 1 ELSE 0 END,
date(datestamp) as date,
r1.group_id