MySQL query SELECT multiple date brackets from table - mysql

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?

Related

Cumulative count for each ID

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.

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))

Count users who have repeatedly called no sooner than 6 days post first call

I have to count how many repeated times a user has called within next 7 days (days have to be flexible) or more.
The query should only consider records with the 7 days earlier than the last date in the table.
My data looks something like this:
call_date user
2017-05-01 100
2017-05-01 500
2017-05-02 200
2017-05-02 300
2017-05-03 300
2017-05-04 100
2017-05-05 400
2017-05-06 500
2017-05-07 600
2017-05-08 200
2017-05-09 700
2017-05-10 500
2017-05-11 400
2017-05-12 300
2017-05-13 100
2017-05-14 200
The desired output of the query is:
call_date user count
2017-05-01 100 2
2017-05-01 500 2
2017-05-02 200 2
2017-05-02 300 2
2017-05-03 300 1
2017-05-04 100 1
2017-05-05 400 2
2017-05-06 500 2
2017-05-07 600 1
Explanation:
While listing the date the first contact should be considered (user 100 called on 2017-05-01, 2017-05-04 and 2017-05-13) but only 2017-05-01 displayed
For user 100, only records within 7 days should be considered hence count of user 100 becomes 2 (2017-05-01 and 2017-05-04; excluding 2017-05-13 since falls out of range) for call_date 2017-05-01
No records after 2017-05-07 are considered because it is the date which is 7 days earlier than the max date i.e. 2017-05-14
This query has to run on 25+ million records hence an optimized query would be added advantage.
I am quite unsure as to how to nail down this problem; a detailed explanation with the query would be much appreciated.
Assuming this is your table definition (I've changed user to user_id to avoid clashing with a reserved keyword):
CREATE TABLE calls
(
call_date date NOT NULL,
user_id integer NOT NULL
/* no primary key. There *can* be duplicate rows, that could be
changed if call_date were instead call_datetime. Then:
PRIMARY KEY (user_id, call_datetime)
Assumed user's cannot make simultaneous calls, nor any faster than
the datetime resolution.
*/
)
;
-- These indexes will help `using index` query plans.
CREATE INDEX idx_calls_user_id_call_date ON calls(user_id, call_date) ;
CREATE INDEX idx_calls_call_date_user_id ON calls(call_date, user_id) ;
... and that we import your data. We can then query the database with:
SELECT
call_date, user_id,
-- Count of the number of calls on `call_date` for `user_id`
count(call_date) AS count_on_date,
-- Count of the number of calls between `call_date` and the next 6 days (including both)
(SELECT count(call_date) FROM calls c1 WHERE c1.user_id = c.user_id AND c1.call_date BETWEEN c.call_date AND c.call_date + interval 6 day) AS count_next_7_days
FROM
calls c
-- The next JOIN is used to retrieve the `reference date`, and do it only once.
-- This will allow to take into account only dates from (2017-05-14 - 13 day) = 2017-05-01 and (2017-05-14 - 7 day) = 2017-05-07
JOIN (SELECT max(call_date) AS ref_date FROM calls) AS d ON c.call_date BETWEEN ref_date - interval 13 day AND ref_date - interval 7 day
GROUP BY
call_date, user_id
ORDER BY
call_date, user_id ;
This query will return:
call_date | user_id | count_on_date | count_next_7_days
:--------- | ------: | ------------: | ----------------:
2017-05-01 | 100 | 1 | 2
2017-05-01 | 500 | 1 | 2
2017-05-02 | 200 | 1 | 2
2017-05-02 | 300 | 1 | 2
2017-05-03 | 300 | 1 | 1
2017-05-04 | 100 | 1 | 1
2017-05-05 | 400 | 1 | 2
2017-05-06 | 500 | 1 | 2
2017-05-07 | 600 | 1 | 1
dbfiddle here
Have you tried DAYOFWEEK() function? This link should be helpful.

Select latest data per group from joined tables

I have two tables like this:
survey:
survey_id | store_code | timestamp
product_stock:
survey_id | product_code | production_month | value
How can I get latest value, based on survey timestamp and grouped by store_code, product_code, and production_month?
for example if I have
survey_id | store_code | timestamp
1 store_1 2015-04-20
2 store_1 2015-04-22
3 store_2 2015-04-21
4 store_2 2015-04-22
survey_id | product_code | production_month | value
1 product_1 2 15
2 product_1 2 10
1 product_1 3 20
1 product_2 2 12
3 product_2 2 23
4 product_2 2 17
It'd return result like this
survey_id | store_code | time_stamp | product_code | production_month | value
2 store_1 2015-04-22 product_1 2 10
1 store_1 2015-04-20 product_1 3 20
1 store_1 2015-04-20 product_2 2 12
4 store_2 2015-04-22 product_2 2 17
and it needs to be as fast as possible, seeing the database is quite large in size
UPDATED - please run query again
Here is my answer:
SELECT survey.survey_id, survey.store_code, survey.timestamp, product_stock.survey_id, product_stock.product_code, product_stock.production_month, product_stock.value
FROM survey
INNER JOIN product_stock
ON survey.survey_id = product_stock.survey_id
WHERE survey.timestamp = (SELECT MAX(timestamp)
FROM survey)
GROUP BY survey.store_code,product_stock.product_code,product_stock.production_month;

mysql complex query for monthly report

employee makes entry in the following table when starting new task
from home or office
[tablename=CHECK]
c_id c_sdate c_emp c_task
-------------------------------------------------
1 2013-05-01 01:01:00 1 26 //date 01 from home-----
2 2013-05-01 08:11:00 1 27 //date 01 from office--- Present
3 2013-05-02 03:41:00 1 28 //date 02 from home---
4 2013-05-02 09:12:00 1 29 //date 02 from office-
5 2013-05-02 22:32:00 1 30 //date 02 from home---Present
6 2013-05-03 01:43:00 1 31 //date 03 from home
7 2013-06-03 23:25:00 1 32 //date 03 from home----------Homework
8 2013-06-03 02:15:00 2 33 //other employee
an employe will be considered as present if there 1 or many records where time between 8am and 8pm
an employe will be considered as workedFromHome if there 1 or many records where time NOT between 8am and 8pm, and not present on that day
note: do not count a day as workedFromHome if there is any record time between 8am and 8pm (means workedFromHome is only counted if he is not resent on that day)
I want to display monthly report of a employee eg. c_emp=1 for month eg. 5
like this in 1 query
c_emp presentCount HW_Count
1 3 1
or separatly query 1
c_emp presentCount
1 3
and query 2
c_emp HW_Count
1 1
I have tried for counting present working fine
select count(distinct(date_format(c_sdate,'%e'))) as count
from ita_check
where date_format(c_sdate,'%m')=5
and c_emp=1
and date_format(c_sdate,'%H%i')>=800
and date_format(c_sdate,'%H%i')<=2000
and for counting fromHome giving wrong count
select count(distinct(date_format(c_sdate,'%e'))) as count
from ita_check
where date_format(c_sdate,'%m')=5
and c_eid=1
and c_id not in (
select c_id
from ita_check
where date_format(c_sdate,'%m')=5
and c_eid=1
and (date_format(c_sdate,'%H%i')<=800 or date_format(c_sdate,'%H%i')>=2000)
)
and date_format(c_sdate,'%H%i')<800
or date_format(c_sdate,'%H%i')>2000
in above query for counting Working
the sub query returns 1 and 2
while the outer eliminate c_id=2 but not c_id=1
Try this query
SELECT c_emp,
sum(if(cnt>=1,1,0)) as Office,
count(*)-sum(if(cnt>=1,1,0)) as WFH from (
select c_emp, Date(c_sdate),
sum(if(c_sdate BETWEEN Date(c_sdate) + interval 8 hour
AND Date(c_sdate) + interval 20 hour, 1, 0)) as cnt
from table1
group by c_emp, Date(c_sdate)) tmp
group by c_emp
SQL FIDDLE:
| C_EMP | OFFICE | WFH |
------------------------
| 1 | 2 | 2 |
| 2 | 0 | 1 |
For monthly report
SELECT c_emp, date_format(c_date, '%c %Y') as Mnth,
sum(if(cnt>=1,1,0)) as Office,
count(*)-sum(if(cnt>=1,1,0)) as WFH from (
select c_emp, Date(c_sdate) as c_date,
sum(if(c_sdate BETWEEN Date(c_sdate) + interval 8 hour
AND Date(c_sdate) + interval 20 hour, 1, 0)) as cnt
from table1
group by c_emp, Date(c_sdate)) tmp
group by c_emp,Mnth
SQL FIDDLE:
| C_EMP | MNTH | OFFICE | WFH |
---------------------------------
| 1 | 5 2013 | 2 | 1 |
| 1 | 6 2013 | 0 | 1 |
| 2 | 6 2013 | 0 | 1 |