So I'm working on a schedule system for my job a basically i wanted to know if there is a way where mysql can do something like:
|Monday |tuesday|wendsday|total
|Dan |5am-7am |7am-6pm|6am-11am|
11am-2pm| |2pm-7pm |
5pm-12am|
where i can enter multiple shifts on 1 day for each person in the same cell if needed instead of the name repeating several times like:
Dan|5-4|
Dan|6-8|
and if there is a function to calculate total time in one cell with multiple shifts
There is a way (representing the data as string), but you wouldn't want to do this - you will loose all calculations, searches etc.
You should not try to represent the data in the database exactly as how it looks on paper.
I would make a table like this:
ShiftID|Person|StartTime|EndTime
Making StartTime & EndTime columns of type DATETIME, you will store not only the HH:mm of a shift's start, but also the day. This is helpful when you have a shift which starts on one day and ends in the next, like starting on Monday 2017-05-15 23:00 and ending on Tuesday 2017-05-16 02:00.
You can extract the date only from this filed using MySQL DATE() function and select only those entires which start OR end on this day.
To calculate the shift's duration you can use MySQL function TIMESTAMPDIFF()
You can even use DAYOFWEEK() to get if it is Monday, Tuesday, etc.
About duplicating the person's name - I would make another table, which will match users with their data to IDs an use ID in the column Person, but for a starter and if your data is not big and if speed is not an issue and if typo errors (like Den instead of Dan) are not a problem ... you could use the name directly in this table.
After storing the data in a table like this you could represent it as you wish in HTML (or print).
You can create a third table with the following columns:
person_id int,
start_time datetime,
end_time datetime
Where person_id would be foreign key to Person table and start_time and end_time would be datetime columns. You can then store multiple records for a person in this table and use MySQL's date functions with GROUP BY to generate the report similar to the one in question.
Related
I have a table lets say:
tblHotel
id
start_date
end_date
rate
Now I want to write procedure for update records for date range, say for example I have data:
id start_date end_date rate
1 2016/01/01 2016/01/10 10
2 2016/01/11 2016/01/20 50
Now if a new date range and rate comes from supplier I want to update tables record like new range is.
start_date end_date rate
2016/01/05 2016/01/12 100
Now updated records should be like this:
id start_date end_date rate
1 2016/01/01 2016/01/04 10
2 2016/01/05 2016/01/12 100
3 2016/01/13 2016/01/20 50
I'm not going to write the code for you, but handling overlapping time frame is tricky. You need to handle this as different cases:
If nothing overlaps, then this is simple:
insert into tbl_Hotel(start_date, end_date, rate)
select $start_date, $end_date, $rate
from dual
where not exists (select 1
from tbl_Hotel h
where h.start_date <= $end_date and h.end_date >= $start_date
);
Easy . . . And in the stored procedure the where can be handled using if logic.
Then the hard part. There are four types of overlaps:
-------hhhhhhhhhhh--------
a) ---------xxxxx------------
b) -----xxxxxx---------------
c) ----------xxxxxx----------
d) --xxxxxxxxxxxxxxxxxxxxxx--
And, then it gets a bit more complicated because a new rate period could overlap with more than one existing period.
Arrrg! How do you approach this? Carefully and with test cases. You might even want to use a cursor (although there are non-cursor-based methods as well).
The idea is to pull out one overlapping existing period. Then, for that period handle the logic:
a) The existing period needs to be split into two parts (with appropriate end dates. Then the new reservation can just be added.
b) The start date of the existing period has to change to one more than the end date of the new one. Then the new one inserted.
c) The end date of the existing period has to change to one less than the start date of the new one. Then the new one inserted.
d) The old record is removed and the new one inserted.
As I say, good tests for your stored procedure are important, so you can actually check that it works.
I have a MySQL table called event to record the whole month data, and it has one column called EventTime to record the time each of them been written into database.
Could I query the data in specific time range, regardless of their date?
For Instance, I want to query the data between 12:00 and 18:00, then it could return all data which occur between the time range in the whole month?
I believe I could do it with a for-loop in my C# code, but I'd like to know is there any SQL command I could use?
You cast the column to TIME and query it.
example:
select time(event_time) from events where time(event_time) BETWEEN '10:00' and '11:00'
the downside of this approach is that the DB won't use any index on event_time (unless you created a function based index on time(event_time))
you can use Time Function here is complete detail of Date and Time Functions
-- it will pull all records within current Month i.e December Now and given Time Range.
Select Time(EventTime) from event where MONTH(EventTime) = Month(Current_Date) and time(EventTime) BETWEEN '12:00' and '18:00'
first off: I know virtually nothing about MS Access but now I'm in a situation where I have to use it (dataset is too big for Excel). The data has column names like Customer_Name, Product Name, Amount, Date
Date refers to the last day of a month, so for example for February it's 28/02/2013. Now I want to compare the amount a customer bought in February to the amount he/she bought in January and calculate the difference. So far, I've been able to this by prompting the user to enter the date.
SELECT Data.Customer_Name,
Sum(IIf(Format(Date,"yymm")=[Startdate (yymm)?],Amount,0)) AS Amount_Startdate,
Sum(IIf(Format(Date,"yymm")=[Enddate (yymm)?],Amount,0)) AS Amount_Enddate,
Amount_Enddate-Amount_Startdate AS Difference
FROM Data
GROUP BY Data.Customer_Name;
This works but is it possible for Access to recognize which dates are in the column "Date" (there are only two distinct dates) so the user does not have to enter anything? Also, I tried to replace "Amount_Startdate" with a field that has the respective date in its name (e.g. "Amount_Feb2013") and played around with ampersand but it didn't work.
If you create a new table called tblValues with just 2 fields; ID and TDate (always try to avoid using reserved words like "Date", "System" or other words that Access already assigns a function to), you can fill it like this:
ID TDate
-- ---------
ST 1/31/2014
EN 2/28/2014
Then you could use the DLookup function to make this code generic:
SELECT Data.Customer_Name,
Sum(IIf(Format(Date,"yymm")=DLookup(Format(TDate, "yymm"), tblValues, "ID = 'ST'"),Amount,0)) AS Amount_Startdate,
Sum(IIf(Format(Date,"yymm")=DLookup(Format(TDate, "yymm"), tblValues, "ID = 'EN'"),Amount,0)) AS Amount_Enddate,
Amount_Enddate-Amount_Startdate AS Difference
FROM Data
GROUP BY Data.Customer_Name;
Then you could just update the table with the values you want to use as start and end dates whenever you want.
I have the following mysql table:
tasks:
=====================
tid
status
desc
duedate
And i have the following records in that table:
records
===========================
1
active
Test description
08/15/2014
2
active
Another description
08/31/204
I am trying to get the days that there is a task for, in that particular month. I have the following query but when i run it it gets both records but "day" is null on both of them for some reason. Can someone please help me with this.
MYSQL QUERY
====================
SELECT DATE_FORMAT(due_date,'%d') AS day FROM tasks WHERE due_date BETWEEN '08/01/2014' AND '08/31/2014'
Try:
SELECT DAY(due_date) AS day
FROM tasks
WHERE due_date >= '2014-08'
AND due_date < '2014-09';
DAY() is a better function for what you want and I prefer using >= and < than BETWEEN for date comparisons, as it allows you to specify precise ranges more easily. Here, for example, you don't need to know the number of days in the month.
I have also used the default date format, which is preferable. If you need the, in my opinion, cray American date format, use DATE_FORMAT() in your SELECT.
This will only work with DATE, DATETIME and TIMESTAMP columns, which is how your due_date should be stored, preferably DATE.
UPDATE
To convert the VARCHAR column to DATE run:
UPDATE tasks SET due_date=STR_TO_DATE(due_date,'%m/%d/%Y')
Then change the type. Also remember to change your INSERT statements to use the default format.
You've got to convert those "date" strings to proper date values with STR_TO_DATE:
SELECT
DAY(STR_TO_DATE(due_date,'%m/%d/%Y')) AS day
FROM tasks
WHERE
STR_TO_DATE(due_date, '%m/%d/%Y')
BETWEEN STR_TO_DATE('08/01/2014' '%m/%d/%Y')
AND STR_TO_DATE('08/31/2014', '%m/%d/%Y')
else you're comparing strings instead.
Note:
It would be better to use a proper DATE or DATETIME column instead.
With the current VARCHAR format MySQL is unable to use indexes. That's very bad for performance.
You can convert your data by adding another column to your table:
ALTER TABLE tasks
ADD COLUMN new_due_date DATE;
Then you use an UPDATE statement to fill this new column
UPDATE tasks
SET new_due_date = STR_TO_DATE(due_date, '%m/%d/%Y');
If you don't need your old column anymore then you can delete this column and modify the new column to have the name of the old one. Then you will have your table with all your data in a DATE column.
I have the following table in MySQL that records event counts of stuff happening each day
event_date event_count
2011-05-03 21
2011-05-04 12
2011-05-05 12
I want to be able to query this efficiently by date range AND by day of week. For example - "What is the event_count on Tuesdays in May?"
Currently the event_date field is a date type. Are there any functions in MySQL that let me query this column by day of week, or should I add another column to the table to store the day of week?
The table will hold hundreds of thousands of rows, so given a choice I'll choose the most efficient solution (as opposed to most simple).
Use DAYOFWEEK in your query, something like:
SELECT * FROM mytable WHERE MONTH(event_date) = 5 AND DAYOFWEEK(event_date) = 7;
This will find all info for Saturdays in May.
To get the fastest reads store a denormalized field that is the day of the week (and whatever else you need). That way you can index columns and avoid full table scans.
Just try the above first to see if it suits your needs and if it doesn't, add some extra columns and store the data on write. Just watch out for update anomalies (make sure you update the day_of_week column if you change event_date).
Note that the denormalized fields will increase the time taken to do writes, increase calculations on write, and take up more space. Make sure you really need the benefit and can measure that it helps you.
Check DAYOFWEEK() function
If you want textual representation of day of week - use DAYNAME() function.