I am creating a clock-in time system and so far I have been able to get user clock in time for today and user clock in time for the current week.
The final step is to get user current time for the current pay period.
I have created a list of pay period start & end dates in Excel.
Whenever you use a function like Excel WEEKNUM() or MySQL YEARWEEK(), these functions come with an additional option parameter.
The links below show the differences between these modes in a table.
Excel WEEKNUM() table reference
MySQL YEARWEEK() table reference
My question is, if we do payroll biweekly, which mode do I set in Excel WEEKNUM() that corresponds to MySQL YEARWEEK()?
Attached spreadsheet clock.logic.xlsx
Thank you for any help.
At first the good news: The Excel ISOWEEKNUM function corresponds to the MySQL WEEKOFYEAR which is WEEK(date,3). So determining ISO week numbers is possible.
But all other WEEK modes are simply crap because the definition of the first week in year does not fit any logic used elsewhere. For example, take the simplest mode having Sunday as the first day of the week and the first week of the year is the week, the first day of the year falls in. This is what Excels WEEKNUM function returns with Return_type 1 or omitted. This should be MySQLs WEEK in modus 0 (0-53) or 2 (1-53). But what the heck?
SELECT WEEK('2008-01-01',0); -> 0
SELECT WEEK('2008-01-01',2); -> 52
So MySQL tells us, Tuesday, 2008-01-01, is in week 52 of 2007?
Really? Why?
Because the rule "Week 1 is the first week … with a Sunday in this year" is not fulfilled by MySQL. Instead it seems for MySQL the first week starts with the first Sunday in this year.
So except of the ISO week numbers, all other week numbers from MySQL are wrong. One could think: Let us take modus 0 and simply add 1 to the result. But that fails in 2012. Because there 2012-01-01 is Sunday and there MySQL gives week number 1 in modus 0 as well as in modus 2.
Examples:
Excel:
Date WEEKNUM ISOWEEKNUM
2008-01-01 1 1
2008-02-01 5 5
2008-02-03 6 5
2008-02-04 6 6
2008-12-31 53 1
2009-01-01 1 1
2009-02-01 6 5
2009-12-31 53 53
2012-01-01 1 52
2012-02-01 5 5
2012-12-31 53 1
2016-01-01 1 53
2016-02-01 6 5
2016-12-31 53 52
MySQL:
drop table if exists tmp;
create table tmp (d date);
insert into tmp (d) values
('2008-01-01'),
('2008-02-01'),
('2008-02-03'),
('2008-02-04'),
('2008-12-31'),
('2009-01-01'),
('2009-02-01'),
('2009-12-31'),
('2012-01-01'),
('2012-02-01'),
('2012-12-31'),
('2016-01-01'),
('2016-02-01'),
('2016-12-31');
select d as 'Date', week(d,0), week(d,3) from tmp;
Result:
Date week(d,0) week(d,3)
2008-01-01 0 1
2008-02-01 4 5
2008-02-03 5 5
2008-02-04 5 6
2008-12-31 52 1
2009-01-01 0 1
2009-02-01 5 5
2009-12-31 52 53
2012-01-01 1 52
2012-02-01 5 5
2012-12-31 53 1
2016-01-01 0 53
2016-02-01 5 5
2016-12-31 52 52
If you want to calculate hours in current pay period in Excel, given a two week pay period, then I'd suggest that you don't need week numbers at all (in fact that overcomplicates the calculation, especially at the start or end of the year)
If you have dates in A2:A100 and hours worked on those dates in B2:B100, and a list of pay period start dates in Z2:Z10 then you can get hours in current pay period with this formula
=SUMIF(A2:A100,">="&LOOKUP(TODAY(),Z2:Z10),B2:B100)
I imagine your actual setup is more complicated, but some variation on the above can probably still be used
Related
I have data such as these:
id year month day
1 2020 11 1
2 2020 11 1
3 2020 12 31
4 2020 12 31
5 2021 1 1
6 2021 1 1
7 2021 1 31
8 2021 1 31
9 2021 2 1
10 2021 2 12
I wish to SELECT all rows between 2 dates.
I realise that I could convert the year/month/day to a timestamp which would make this very easy. Actually the timestamp is already there, however, the underlying table is huge (tens of billions of rows) and the DB administrator has set up indexing/clustering on the year/month/day columns in order provide performant queries. Queries that directly use the actual timestamp in a WHERE clause take far too long to run (hours) whereas queries that use year/month/day run within seconds.
Here is a db<>fiddle
Just to clarify, this is a way to do it, but your problem is your DBA, your arquitechture, etc. etc. You won't solve this by this way, neither the time or resources wasted. Maybe you need to ask a proper way to do this with non SQL database in DBA stack exchange site.
Anyway, for the to-know way:
Convert data to datestamp ISO: yyyyMMdd with CONCAT and LPAD
Compare the data as normal integer
Example: (of course you can change the values of your search)
SELECT * from dt WHERE CONCAT(year,LPAD(month, 2, '0'),LPAD(day, 2, '0')) BETWEEN 20201231 AND 20210101
How can I select all rows from a table where a date column is within a specific range of dates, at a given period (e.g. every 14 days)?
The table has a date column with most every date represented, possibly multiple times. The range is defined by a start date and an end date. The period is a number of days. For example:
Start: 2016-01-01 (friday)
End: 2016-12-31 (saturday)
period: 14 (days)
For the above, the query should return rows for every other Friday in 2016. That is, it should return the rows for the following dates:
2016-01-01
2016-01-15
2016-01-29
2016-02-12
2016-02-26
2016-03-11
2016-03-25
2016-04-08
2016-04-22
2016-05-06
2016-05-20
2016-06-03
2016-06-17
2016-07-01
2016-07-15
2016-07-29
2016-08-12
2016-08-26
2016-09-09
2016-09-23
2016-10-07
2016-10-21
2016-11-04
2016-11-18
2016-12-02
2016-12-16
2016-12-30
Currently, this is done in a stored procedure where a loop fills a temp table with the target dates, which is later joined on. However, I am trying to rewrite this code to step away from stored procedures.
What would be the best way to get the desired rows without using the stored procedure & a temp table? Keep in mind that (one of) the table(s) is quite large at around 1M records indexed on date, so any calculated values might impact the performance severely.
Alternatively, I could calculate all dates in the interval in PHP/RoR and use a massive IN clause, but hopefully there is a better solution.
Try this:
table_name1 is your table
date1 the date field
"2022-01-02" the start (twice included)
"2022-01-10" the end
3 the interval
SELECT date1
FROM table_name1
WHERE date1 BETWEEN "2022-01-02" AND "2022-01-10"
AND (DATE("2022-01-02") - date1) % 3 = 0;
Tested it with MySQL 5.6.
I have a MySQL table similar to this:
item | order | start date | end date
------------------------------------------
1 1 2015-09-15 2015-09-20
2 1 2015-09-15 2015-09-20
1 2 2015-09-20 2015-09-25
2 2 2015-09-20 2015-09-25
What I want to do is execute a query that will check if any end-dates are within 7 days of a future start date, and return the result. Does anyone know how this could be done?
EDIT: Should be more specific I suppose - the start date and end date of an order (say in this case order 2 from the example table) can be within 7 days of each other. I want to check if order 1's end date is within 7 days of order 2's start date. Sorry if that wasn't clear before.
You can use datediff function.
select * from table_name
where
start_date > curdate()
and datediff(end_date,start_date) between 0 and 7
I am currently working on a platform where I would like to offer some rentals.
I want to store all possible rental types in the database, so I do not need to take care of logic in code.
Basically I want to offer following rental-times:
1 day
7 days
5 days / need to be weekdays ( which is monday to
friday )
2 days / weekend ( needs to be saturday till sunday )
1 month / which will be from e.g. 14 of some month till 13th of following month
For the time of days I thought of storing data in minutes, this is easy to figure out.
If there is a weekday condition I thought of using the DAYOFWEEK Indexes, so I could define for 5 days, the first day of rental needs to have index 2 which is Monday, for weekend I could define that the day of rental needs to have index 6, which is Saturday.
rental_type_id | rental_time_in_minutes | rental_label | rental_start_day_indexes
1 day would be like
1 | 1440 | 1 day | 1,2,3,4,5,6,7
7 days
2 | 10080 | 7 days | 1,2,3,4,5,6,7
5 days
3 | 7200 | Weekdays | 2,3,4,5,6
etc.
Is this a way to go for, or should I store the rental time just in days?
Any help, advice, critics or cheers are helpful!
Thanks.
Depending on how you use this, storing rental time in minutes could cause issues around DST where you have 23 or 25 hours in a day.
Also storing the indices as comma-separated lists will cause you problems. I would make a mapping table. That column is not in normal form and will be tough to query.
I would honestly just make different tables for the different durations.
I would store the durations in seconds. Because it makes the whole thing easier to query and more felxible. Lets say you have those rental durations. Table durations:
d_id type duration
1 1 day 01
2 3 days 03
3 7 days 07
I would suggest that you use normal timestamps for the rentals. I would store the start and end timestamp. Lets say you have the following table.
In this example I'm using days instead of a timestamp just to make it easier to show. Let's say today is day 3. Table rentals:
customer start end
Bob 02 05
Joe 10 11
Ian 03 04
Let's say you want to want to get all the currently active rentals (Bob & Ian). You can fetch it like this:
SELECT * FROM `rentals` WHERE `start`<3 AND 3<`end`
You can find all which of rental type "1 day" (Ian) by using this query:
SELECT * FROM `rentals`,`durations` WHERE `end`-`start`=`duration` and `d_id`=1
The advantage of using timestamps is that you can very precisely set the rental start and end time. You can check how many hours and minutes the customer is too late with giving the object back. Then you can easily calculate the exact additional fees.
In the project I'm working on right now the system stores employees' timetables in the table with the following structure:
employee_id | mon_h_s | mon_m_s | mon_h_e | mon_s_e | tue_h_s | tue_m_s | etc.
------------------------------------------------------------------------------
1 06 00 14 30 06 00 ...
2 18 30 07 00 21 00 ...
where:
mon_h_s - monday hours start
mon_m_s - monday minutes start
mon_h_e - monday hours end
mon_m_e - monday minutes end
tue_... - tuesday...
Every day of the week has 4 fields: hours start, minutes start, hours end, minutes end.
So, from the table above we can see that:
employee with the id 1 works from 06:00 to 14:30 on Monday
employee with the id 2 works from 18:30 to 07:00 on Monday (basically, between Monday and Tuesday, at night)
The problem is that I'm not sure how to create a SQL query which takes into account everything including time overlapping (at night time). For example, we need to find an employee who works at 6am (06:00) on Tuesday. In our case both employees (id 1 and id 2) would satisfy this criteria. Employee with the id 1 starts his work at 06:00 on Tuesday, and employee with the id 2 works until 07:00 Tuesday (starts on Monday though).
Any suggestions on how to solve this problem would be greatly appreciated.
Probably something like:
SELECT (1440 + ((mon_h_e*60)+mon_m_e) - ((mon_h_e*60)+mon_m_e)) % 1440
This will give you the time worked in minutes. Basically, it adds 1440 (minutes in a day, or 24h*60min/h) to the difference between end time and start time, and keep the rest (modulo) of 1440.
Now for the design part:
If you can, redesign your table. Your table need not have all days of the week in one row, that will make tallying of weekly times very tedious.
You should consider using real datetimes.
employee_id | entrytime | exittime
1 | 2011-10-31 06:00:00 | 2011-10-31 14:30:00
1 | 2011-11-01 06:00:00 | null
2 | 2011-10-31 18:30:00 | 2011-11-01 07:00:00
2 | 2011-11-01 21:00:00 | null
That way, you have:
Full access to all date and time functions in MySQL
Easy calculation of duration
Easy filtering on incomplete periods
There are four basic cases that you need o handle
A -> when time of lecture starts before given time
B -> when time of lecture starts after given time but falls within range of ending time
C -> when time of lecture starts within given time but ends after
D -> when time of lecture starts before given time and ends after given time
Now, this can be accomplished using simple OR conditions