Records added since specific month this year in SQL - mysql

I have a table which contains the following data
userId | name | from
1 | aaa | 2020-09-23
2 | bbb | 2020-09-01
3 | ccc | 2019-05-12
4 | ddd | 2019-06-01
5 | eee | 2018-06-23
6 | fff | 2018-07-23
It is for an educational purpose and therefore the year runs from September to August rather than January to December. How do I output all of the users who were added since the previous September (so if it's October 2020 then 1 month ago, if it's January 2021 then 4 months ago)? The query has to be relative so that it always outputs the previous September to the time that the query is run rather than a specific September.
The result of the query should be
bbb 2020-09-01
aaa 2020-09-23

With NOT EXISTS:
select t.* from tablename t
where t.`from` >= concat(year(current_date), '-09-01')
and not exists (
select 1 from tablename
where name = t.name
and `from` between
concat(year(current_date), '-09-01') - interval 1 year
and
concat(year(current_date), '-09-01') - interval 1 day
)
Or maybe:
select t.* from tablename t
where t.`from` >= concat(year(current_date) - (month(current_date) < 9), '-09-01')
and not exists (
select 1 from tablename
where name = t.name
and `from` between
concat(year(current_date) - (month(current_date) < 9), '-09-01') - interval 1 year
and
concat(year(current_date) - (month(current_date) < 9), '-09-01') - interval 1 day
)
so if you execute the query in say March 2021, you will get the correct results that compare the current educational year with the previous one.
See the demo.
Results:
> userId | name | from
> -----: | :--- | :---------
> 1 | aaa | 2020-09-23
> 2 | bbb | 2020-09-01

You can subtract 9 months and compare to the year:
where year(`from` - interval 9 month) = year(curdate() - interval 9 month)
Actually, you might want year(curdate()) +/- 1 depending on how you are identifying the year.

Related

How to select count today and tomorrow data less than specific time group by day?

I have a table like a table below.
I want to select count and group by day.
But the data in 1 day will start counts at 7:00:00 until tomorrow at 6:59:59 (24hr.).
For example
Day 1 data between '2019/06/01 7:00:00' and '2019/06/02 06:59:59'
Day 2 data between '2019/06/02 7:00:00' and '2019/06/03 06:59:59'
How can I code the where condition?
id | create_date | judge |
-----+---------------------+---------+
1 | 2019-06-02 8:00:00 | ok |
2 | 2019-06-02 9:00:00 | ok |
3 | 2019-06-02 10:00:00 | ok |
4 | 2019-06-02 11:00:00 | ok |
5 | 2019-06-02 15:00:00 | ok |
6 | 2019-06-03 4:00:00 | ok |
7 | 2019-06-03 5:00:00 | ok |
8 | 2019-06-03 8:00:00 | ok |
9 | 2019-06-03 9:00:00 | ok |
10 | 2019-06-03 9:00:00 | fail |
I've tried below but the result is not as expected.
SELECT COUNT(*),DAY(create_date)
FROM mytable
WHERE judge = 'ok' and MONTH(create_date) = '6' and YEAR(create_date) = '2019' and TIME(create_date) > '07:00:00'
Group by DAY(create_date) order by DAY(create_date) ASC
Expected results
COUNT(*) | DAY(create_date) |
-----------+---------------------+
7 | 2 | (from id 1 to 7)
2 | 3 | (from id 8 and 9)
You could subtract seven hours from each date, truncate them to show the date only and then group them:
SELECT DATE(DATE_SUB(create_date, INTERVAL 7 HOUR)), COUNT(*)
FROM mytable
-- Where clause if you need it...
GROUP BY DATE(DATE_SUB(create_date, INTERVAL 7 HOUR))
Just subtract 7 hours for the aggregation and the date/time comparisons:
SELECT DATE(create_date - interval 7 hour) as dte, COUNT(*)
FROM mytable
WHERE judge = 'ok' and
create_date >= '2019-06-01 07:00:00' AND
create_date < '2019-07-01 07:00:00'
GROUP BY DATE(create_date - interval 7 hour)
ORDER BY dte;
Try this-
SELECT
CAST(DATE_SUB(create_date, INTERVAL 7 HOUR) AS DATE),
COUNT(*)
FROM YOUR_TABLE
GROUP BY CAST(DATE_SUB(create_date, INTERVAL 7 HOUR) AS DATE)

Find all fridays with date in the year 2017

I want a MySQL query that will fetch all Fridays with date for the year 2017.
I know that SQL query for the same is:
SELECT Fridays = DATEADD(yy, DATEDIFF(yy, 0, GETDATE()), n.num)
FROM (SELECT TOP 366 num = ROW_NUMBER() OVER(ORDER BY a.NAME)-1 FROM dbo.syscolumns a, dbo.syscolumns b) n
WHERE DATENAME(weekday, DATEADD(yy, DATEDIFF(yy, 0, GETDATE()), n.num)) = 'Friday'
I am looking for a MySQL alternative for the same.
This is an exact conversion of your sql logic in mysql
SELECT DATE_ADD(MAKEDATE(year(now()),1), INTERVAL #num:=#num+1 DAY)
From (select #num:=-1) num
where DAYNAME(DATE_ADD(MAKEDATE(year(now()),1), INTERVAL #num:=#num+1 DAY))="Friday"
limit 365
Mysql does not have row_number function until version 8. Prior to version 8 row_number can be simulated using variables.
select s.num , date_add(str_to_date(concat('2016','/','12','/','31'),'%Y/%m/%d'), interval s.num day) dt,
dayname(date_add(str_to_date(concat('2016','/','12','/','31'),'%Y/%m/%d'), interval s.num day)) dy
from
(
select #num:=#num + 1 num from information_schema.columns,(select #num:=0) n
limit 35
) s
where dayname(date_add(str_to_date(concat('2016','/','12','/','31'),'%Y/%m/%d'), interval s.num day)) = 'Friday';
information_schema.columns is similar to dbo.syscolumns.
------+------------+--------+
| num | dt | dy |
+------+------------+--------+
| 6 | 2017-01-06 | Friday |
| 13 | 2017-01-13 | Friday |
| 20 | 2017-01-20 | Friday |
| 27 | 2017-01-27 | Friday |
| 34 | 2017-02-03 | Friday |
+------+------------+--------+
5 rows in set, 2 warnings (0.26 sec)
SELECT * FROM table WHERE ([date] BETWEEN date_start and date_end) AND
DAYNAME([date])='Friday'
Source of the query: Get data for every friday between two dates

MySQL record between fixed date range

I have an small application which was build with CodeIgniter 3 and need to perform a report which will be converted to Chart.js. The report should be in yearly basis but at given specific date every month. The requirement are all data count must be from 4th to 3rd monthly. Like this:
For example January Report would be from 4th January to 3rd February, 4th February to 3rd March,... and so on.
I have created a MySQL query but I'm stuck on how to get the date too date. My Query are as follows:
SELECT DATE_FORMAT(odd_date_created, '%Y') as 'year',
DATE_FORMAT(odd_date_created, '%m') as 'month',
COUNT(odd_id) as 'total', status
FROM odd_data
WHERE status = $id and
GROUP BY DATE_FORMAT(odd_date_created, '%Y%m'), status
I'm new to MySQl. Could somebody help me on this. I'm stuck where should I put the date to date query.
Firstly I want to caution you not to use "between" with the following when you come to join your data, use this method instead data.date >= r.period_start_dt and data.date < r.period_end_dt
Secondly I am assuming your data does have dates or timestamps and that will fall between the calculated ranges that follow:
set #year :=2017;
select
*
from (
select
start_dt + INTERVAL m.n MONTH period_start_dt
, start_dt + INTERVAL m.n + 1 MONTH period_end_dt
from (
select str_to_date(concat(#year,'-01-04'),'%Y-%m-%d') start_dt ) seed
cross join (select 0 n union all
select 1 union all
select 2 union all
select 3 union all
select 4 union all
select 5 union all
select 6 union all
select 7 union all
select 8 union all
select 9 union all
select 10 union all
select 11
) m
) r
## LEFT JOIN YOUR DATA
## ON data.date >= r.period_start_dt and data.date < r.period_end_dt
Example ranges: (produce you own at this demo: http://rextester.com/CHTKSA95303 )
nb dd.mm.yyyy (.de format)
+----+---------------------+---------------------+
| | period_start_dt | period_end_dt |
+----+---------------------+---------------------+
| 1 | 04.01.2017 00:00:00 | 04.02.2017 00:00:00 |
| 2 | 04.02.2017 00:00:00 | 04.03.2017 00:00:00 |
| 3 | 04.03.2017 00:00:00 | 04.04.2017 00:00:00 |
| 4 | 04.04.2017 00:00:00 | 04.05.2017 00:00:00 |
| 5 | 04.05.2017 00:00:00 | 04.06.2017 00:00:00 |
| 6 | 04.06.2017 00:00:00 | 04.07.2017 00:00:00 |
| 7 | 04.07.2017 00:00:00 | 04.08.2017 00:00:00 |
| 8 | 04.08.2017 00:00:00 | 04.09.2017 00:00:00 |
| 9 | 04.09.2017 00:00:00 | 04.10.2017 00:00:00 |
| 10 | 04.10.2017 00:00:00 | 04.11.2017 00:00:00 |
| 11 | 04.11.2017 00:00:00 | 04.12.2017 00:00:00 |
| 12 | 04.12.2017 00:00:00 | 04.01.2018 00:00:00 |
+----+---------------------+---------------------+
Given the specification, I think I would tempted to cheat it... subtract 3 days from the date. Doing that, Jan 4 backs up to Jan 1, Feb 3 backs up to Jan 31... so those all end up as January.
SELECT DATE_FORMAT(odd_date_created + INTERVAL -3 DAY, '%Y') AS `year`
, DATE_FORMAT(odd_date_created + INTERVAL -3 DAY, '%m') AS `month`
, ...
FROM ...
GROUP
BY DATE_FORMAT(odd_date_created + INTERVAL -3 DAY, '%Y')
, DATE_FORMAT(odd_date_created + INTERVAL -3 DAY, '%m')
This falls apart if there's oddball ranges... if it's not always the 4th and 3rd.

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 |

SQL query to calculate hours spent from the the other day and ending up on the next day

TableName: TimeLog
TimeLogID | EmployeeID | TimeLog
------------------------------------------
1 | 1 | 1/1/2013 11:00 PM
2 | 1 | 1/2/2013 07:00 AM
3 | 1 | 1/2/2013 11:00 PM
4 | 1 | 1/3/2013 07:00 AM
TableName: Schedule
ScheduleID | EmployeeID | TimeIN | TimeOUT
----------------------------------------------
1 | 1 | 11:00 PM | 07:00 AM
My problem here is how could I make a query to calculate the hours spent by an employee given that he or she started working at 11 PM then end up at 7 AM. Hope someone could help me with this problem. Thanks.
Basically, I need the hours worked in every working day.
This is Oracle query to calc time diff only. I think it should work in any SQL if you replace dual with your table. There are LAG/LEAD functions to compare prev/next row values but I do not know if those are available in your version of SQL. I hope this is useful to you:
SELECT trunc(mydate / 3600) hr
, trunc(mod(mydate, 3600) / 60) mnt
, trunc(mod(mydate, 3600) / 60 /60) sec
FROM
(
SELECT (to_date('01/02/2013 23:00:00', 'mm/dd/yyyy hh24:mi:ss') -
to_date('01/01/2013 07:00:00', 'mm/dd/yyyy hh24:mi:ss')) * 86400 mydate
FROM dual
)
/
You can use this query
select
e.TimeLogID,
e.EmployeeID,
ifnull(TIMESTAMPDIFF(HOUR,e.TimeLog,la.TimeLog),0) as timediff
from emp_time as e
left join (
select
*
from emp_time
) as la on la.TimeLogID = (
select
min(TimeLogID )
from emp_time
where TimeLogID > e.TimeLogID
limit 1
);
Output
TimeLogID EmployeeID timediff
1 1 20
2 1 4
3 1 20
4 1 0