I am working on a booking system where users can book certain services online. I am stuck on finding and displaying available time slots within a specific day. I know the length of the needed time slot is 1 hour and the business hours.
Is there a way to show time slots that has not yet been booked on a certain day and display only the available time slots that is available to be booked in a dropdown select form?
If a customer selects a specific day and clicks "Select Day" then it needs to query the DB and return the results.
My SQL structure is as follows
|id | title | start_time | end_time | booking_date |
| 1 | Name1 | 2022-05-12 08:00:00 | 2022-05-12 09:00:00 | 2022-05-12 |
| 2 | Name2 | 2022-05-12 10:00:00 | 2022-05-12 11:00:00 | 2022-05-12 |
| 3 | Name3 | 2022-05-12 13:00:00 | 2022-05-12 14:00:00 | 2022-05-12 |
| 4 | Name4 | 2022-05-12 14:00:00 | 2022-05-12 15:00:00 | 2022-05-12 |
as per above the select form should display the timeslots that is not already taken.
09:00 - 10:00
12:00 - 13:00
15:00 - 16:00
It would be something like:
select
id, title
from
<table>
where
start_time between '2022-05-12 00:00:00' and '2022-05-12 11:59:59'
and
booking_date is null
I don't know the name of your table, so you would need to replace <table> with that. I'm also assuming that "booking_date" will have a value to indicate that time slot has been reserved, that it's a date field, and it will be null if that slot hasn't been selected. However, booking_date could have a different purpose.
This is a lazy answer
(because I think just use SQL will do it, use subSelect and other function, but I don't know how to do, sorry.)
get today occupy time:
SELECT id, TIME(start_time) AS s_time FROM tablename
WHERE start_time >= '2022-05-12 00:00:00'
AND start_time < '2022-05-13 00:00:00'
diff time in php:
$sqlResult = []; // sql result
$timeAll = [
'00:00:00',
'01:00:00',
'02:00:00',
'03:00:00',
... // TODO: we need fill it
'23:00:00',
];
foreach ($sqlResult as $item) {
if (isset($timeAll[$item['s_time']])) {
unset($timeAll[$item['s_time']]);
}
}
return $timeAll;
// TODO: javascript or other client code can use it.
ref knowledge link:
MySQL SELECT WHERE datetime matches day (and not necessarily time)
If you choose 2022-05-26, and Peter is occupying room F25 from 2022-05-16 until 2022-05-29, it means the date you select must be out of this range.
So, the query below will only return rooms that were not booked on that day.
SELECT b.id, b.room_id as available_room FROM booking as b
WHERE(
unix_timestamp('$mydate')
NOT BETWEEN unix_timestamp(b.start_date)
AND unix_timestamp(b.end_time)
)
AND unix_timestamp(b.end_time) < unix_timestamp('$mydate');
Assuming $mydate is the variable that contains the date selected by the user, the above query will return rooms that will be available in the future on that particular day.
Related
Assuming that I have a table like this:
+----+----------------+------------+------------+-----------+----------+
| id | time_needed | date_start | date_stop | hour_start| hour_stop |
+----+----------------+------------+------------+-----------+----------+
| 1 | 30 | 2018-08-06 | 2018-08-06 | 08:00:00 | 08:30:00 |
| 2 | 96 | 2018-08-06 | 2018-08-06 | 10:45:00 | 14:21:00 |
| 3 | 20 | NULL | NULL | NULL | NULL |
| 4 | 56 | NULL | NULL | NULL | NULL |
+----+----------------+------------+------------+-----------+----------+
I know when I'll execute the operations 1 and 2, But instead for the 3 and 4 I just know the the time spent to execute the operations (20 and 56 minutes)
How can I check with mysql when I can execute the operation 3? I mean, is there a possibility to check when I have free time and for how long?
Looking at the table I can say that I have free time from the 08:31 to 10:44, but there is a way to check it with mysql?
EDIT
I would like to see the time free, beetween 8 am and 18 pm.
What you are demanding is not (all alone) a task of mysql. mysql can give you the DATA according to your query - but your programming language should add the logic of scheduling entries, whenever possible.
At first i would start with the following database changes:
Combine the date / hour columns into a datetime column.
remove the end_date / end_hour - you always can calcluate this with date_start + time_needed
So, you end up with a datatable like this:
+----+----------------+---------------------+
| id | time_needed | date_start |
+----+----------------+---------------------+
| 1 | 30 | 2018-08-06 08:00:00 |
| 2 | 96 | 2018-08-06 14:21:00 |
+----+----------------+---------------------+
Now, all you need to do is: Join the table with itself, and make sure everything is calculated as it should be:
-- new Task takes 25 Minutes.
SELECT DISTINCT L.* FROM time_table L LEFT JOIN time_table R
-- compare with every later schedule
on L.date_start < R.date_start
WHERE
-- use only rows that have enough time for the task that should be scheduled
(date_add(L.date_start, INTERVAL L.time_needed + 25 MINUTE ) < R.date_start
-- and only in the future
and date_add(L.date_start, INTERVAL L.time_needed MINUTE) > NOW()
-- due to the join, it might happen that we ignore entries in between.
-- make sure, there is no other task in the calculated timespan!
and not exists
(SELECT id FROM time_table x WHERE
x.date_start > L.date_start AND
x.date_Start < date_add(L.date_start, INTERVAL L.time_needed + 25 MINUTE) )
)
-- and ofc. the last row in the schedule.
OR isnull (R.date_start);
This returns both datarows, as 25 minutes can be scheduled right after every other task.
http://sqlfiddle.com/#!9/02020d8/1
14:21 - 08:00 is 6:21, and 30 minutes are "booked". So the gap is 5:51 - so a 350 Minute Task should fit after 08:00 - a 351 Minute Task not:
350 minutes to be scheduled:
http://sqlfiddle.com/#!9/02020d8/2
351 minutes to be scheduled:
http://sqlfiddle.com/#!9/02020d8/3
All you got to do afterwards:
Take the smalles id, and insert your schedule right after it. Remember, date_start will be prior_date_start + prior_time_needed.
See this example as well: Scheduling a 20 minute Task would have 3 options with the example data (Added 2 columns for your convenience):
http://sqlfiddle.com/#!9/02020d8/8
I need to create a date range in a table that houses transaction information. The table updates sporadically throughout the week from a manual process. Each time the table is updated transactions are added up to the previous Sunday. For instance, the upload took place yesterday and so transactions were loaded through last Sunday (Feb 26th). If it had been loaded on Wednesday it would still be dated for Sunday. The point is that I have a moving target with my transactions and also when the data is loaded to the table. I am trying to fix my look back period to the date of the latest transaction then go three weeks back. Here is the query that I came up with:
SELECT distinct TransactionDate
FROM TransactionTABLE TB
inner join (
SELECT distinct top 21 TransactionDate FROM TrasactionTABLE ORDER BY TransactionDate desc
) A on TB.TransactionDate = A.TransactionDate
ORDER BY TB.TransactionDate desc
Technically this code works. The problem that I am running into now is when there were no transactions on a given date, such as bank holidays (in this case Martin Luther King Day), then the query looks back one day too far.
I have tried a few different options including MAX(TransactionDate) but if I use that in a sub-query or CTE then use the new value in a WHERE statement as a reference I only get the max value or the value I subtract that statement by. For instance if I say WHERE TransactionDate >= MAX(TransactionDate)-21 and the max date is Feb 26th then the result is Feb 2nd instead of the range of dates from Feb 2nd through Feb 26th.
IN SUMMARY, what I need is a date range looking three weeks back from the date of the latest transaction date. This is for a daily report so I cannot hardcode the date in. Since I am also using Excel Connections the use of Declare statements is prohibited.
Thank you StackOverflow gurus in advance!
You could use something like this:
;with n as (select n from (values(0),(1),(2),(3),(4),(5),(6),(7),(8),(9)) t(n))
, dates as (
select top (21)
[Date]=convert(date,dateadd(day, row_number() over (order by (select 1))-1
, dateadd(day,-20,(select max(TransactionDate) from t) ) ) )
from n as deka
cross join n as hecto
order by [Date]
)
select Date=convert(varchar(10),dates.date,120) from dates
rextester demo: http://rextester.com/ZFYV25543
returns:
+------------+
| Date |
+------------+
| 2017-02-06 |
| 2017-02-07 |
| 2017-02-08 |
| 2017-02-09 |
| 2017-02-10 |
| 2017-02-11 |
| 2017-02-12 |
| 2017-02-13 |
| 2017-02-14 |
| 2017-02-15 |
| 2017-02-16 |
| 2017-02-17 |
| 2017-02-18 |
| 2017-02-19 |
| 2017-02-20 |
| 2017-02-21 |
| 2017-02-22 |
| 2017-02-23 |
| 2017-02-24 |
| 2017-02-25 |
| 2017-02-26 |
+------------+
I just found this for looking up dates that fall within a given week. The code can be manipulated to change the week start date.
select convert(datetime,dateadd(dd,-datepart(dw,convert(datetime,convert(varchar(10),DateAdd(dd,-1/*this # changes the week start day*/,getdate()),101)))+1/*this # is used to change the week start date*/,
convert(datetime,convert(varchar(10),getdate(),21))))/*also can enter # here to change the week start date*/
I've included a screenshot of the results if you were to include this with a full query. This way you can see how it looks with a range of dates. I did a little manipulation so that the week starts on Monday and references Monday's date.
Since I am only looking back three weeks a simple GETDATE()-21 is sufficient because as the query moves forward through the week it will look back 21 days and pick the Monday at the beginning of the week as my start date.
I have this table (have a look on SQLFiddle)
In previous steps the record number has been determined and the values for "PrevVal" and "NewVal" have been calculated.
The record's end value ("NewVal"), becomes the next record's starting value ("PrevVal")
I would like to condense the table in such a way that there is only one record per day, containing:
the date starting value "StartOfDay",
the total change during the day "TotalChange" and
the resulting day-end value "EndOfDay"
The desired result can be seen in the demo table "ChangesPerDayCondensed"
Who can help me solve this (a stored procedure is OK).
Thnx
I am a little confused whey the record numbers are going the opposite way. But neverthless you could solve this by evaluating the starting value and sum of mutations separatately and then adding them all to come up with ending value..
Ordering the results descending as the record number again needs to be lower for a higher date.
insert into ChangesPerDayCondensed
select #recrd:=#recrd+1, a.MyDate, b.PrevVal, a.Mutation, b.PrevVal+a.Mutation
from
(select MyDate, sum(Mutation) as Mutation from MutationsPerDay group by MyDate) a,
(select b.MyDate, b.PrevVal from (select MyDate, max(RecNo) as RecNo from MutationsPerDay group by MyDate) a, MutationsPerDay b where a.RecNo = b.RecNo) b,
(select #recrd:=0) c
where a.MyDate = b.MyDate order by MyDate desc;
I'd do it this way:
First create a lookup for each day (find first and lasts ReqNo) and then join two times to the Daily table and calculate the changes:
SELECT first_.MyDate,
first_.PrevVal AS StartOfDay,
last_.NewVal AS EndOfDay,
(last_.NewVal - first_.PrevVal) AS TotalChange
FROM
(SELECT mpd1.MyDate,
max(mpd1.RecNo) AS first_rec_no,
min(mpd1.RecNo) AS last_rec_no
FROM MutationsPerDay mpd1
GROUP BY MyDate) AS lo
JOIN MutationsPerDay AS first_ ON lo.first_rec_no = first_.RecNo
JOIN MutationsPerDay AS last_ ON lo.last_rec_no = last_.RecNo
Explanation:
What you actually want is:
For every day the first and the last value (and the difference).
So what you need to find first is for every date the id of the first and the last value:
SELECT mpd1.MyDate,
max(mpd1.RecNo) AS first_rec_no,
min(mpd1.RecNo) AS last_rec_no
FROM MutationsPerDay mpd1
GROUP BY MyDate
----------------------------------------------------
| MyDate | first_rec_no | last_rec_no |
----------------------------------------------------
| 2016-12-05 00:00:00 | 16 | 13 |
| 2016-12-07 00:00:00 | 12 | 12 |
| 2016-12-12 00:00:00 | 11 | 8 |
| 2016-12-14 00:00:00 | 7 | 7 |
| 2016-12-20 00:00:00 | 6 | 6 |
| 2016-12-21 00:00:00 | 5 | 4 |
| 2016-12-28 00:00:00 | 3 | 3 |
| 2016-12-29 00:00:00 | 2 | 2 |
| 2016-12-30 00:00:00 | 1 | 1 |
----------------------------------------------------
Then you can use these first and last id's to find the corresponding values in the source table. For example for the 2016-12-21 you'd get the rows with the id's first: 5 and last: 4
The PrevVal record no 5 represents the first value you have seen at this day and NewVal in record no 4 represents the last value you have seen at this day. If you subtract them you'll get the change for this day.
I hope this clarifies the methodology a bit.
I'm developing a lawyer booking system, where a person can book an appointment at a given time in a given day (the next lawyer's available day).
Let's say it is a ZocDoc for lawyers. The same structure, with appointments based on time: http://goo.gl/djUZb
I'm using MySQL and PHP.
The table schema:
CREATE TABLE `laywer_appointments` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`lawyer_id` INT unsigned,
`day_of_week` tinyint(3) unsigned DEFAULT '1',
`slot_date` date DEFAULT NULL,
`slot_time` time DEFAULT NULL,
`status` tinyint(4) NOT NULL DEFAULT '0',
`client_id` int(11) DEFAULT NULL, -- client_id = NULL means free slot
);
Point 1)
Each lawyer has default time slots based on the day of week (status = 0 means available).
When inserting default slots, I don't provide a date, just day_of_week. Example data:
+-----------+-------------+-----------+-----------+
| lawyer_id | day_of_week | slot_time | status |
+-----------+-------------+-----------+-----------+
| 1 | 1 | 08:00 | 0 |
| 1 | 1 | 08:30 | 0 |
| 1 | 1 | 09:00 | 0 |
| 1 | 1 | 10:30 | 0 |
| 1 | 4 | 14:30 | 0 |
| 1 | 4 | 16:40 | 0 |
| 2 | 1 | 10:20 | 0 |
| 2 | 1 | 14:00 | 0 |
| 2 | 3 | 15:50 | 0 |
+-----------+-------------+-----------+-----------+
Point 2)
A lawyer can add a time slot to a specific day (even if this day is from a different day of week from his default slots) and can also lock (status = -1) one of the default slots in a specific day (i.e. he is on a meeting or he is sick):
+-----------+-------------+-----------+-----------+-----------+
| lawyer_id | day_of_week | slot_time | slot_date | status |
+-----------+-------------+-----------+-----------+-----------+
| 1 | 1 | 16:00 | 12/03/13 | 0 |
| 1 | 6 | 11:00 | 26/04/13 | 0 |
| 1 | 6 | 12:00 | 26/04/13 | 0 |
| 2 | 1 | 10:00 | 01/01/13 | -1 |
+-----------+-------------+-----------+-----------+-----------+
Point 3)
Then we have appointments booked. In this case we fill the slot_date and the client_id:
+-----------+-------------+-----------+-----------+-----------+
| lawyer_id | day_of_week | slot_time | slot_date | client_id |
+-----------+-------------+-----------+-----------+-----------+
| 1 | 1 | 10:30 | 12/03/13 | 10 |
+-----------+-------------+-----------+-----------+-----------+
As an example, with the above booking and assuming it is still 6:30 of the same day (12/03/13), the free available slots that have to be printed are:
8:00 - default slot
8:30 - default slot
9:00 - default slot
16:00 - Specific slot inserted in point 2 for 12/03/13
The problem:
I have to return the next available date and the related free times (default ones, specific ones minus locked ones and booked ones). I can't just say "return times from Monday, 10/10/13".
In a search results page, I'll list all lawyers and the availability time table for each. So that means each lawyer will have a different time table every time a search is made.
I can't simply say "SELECT time FROM [bunch of joins] WHERE date = today".
I came with this query which ignores slots that are locked (status = -1) or booked (client_id not null), but of course it won't return the free times for the closest day with available times (or from today):
SELECT p.day_of_week, p.slot_date, p.slot_time
FROM laywer_appointments p
WHERE p.client_id IS NULL AND p.status = 0
AND p.slot_time NOT IN (
SELECT s.slot_time FROM laywer_appointments s
WHERE (s.slot_date IS NOT NULL AND s.client_id IS NOT NULL
OR s.status = -1) AND s.day_of_week = p.day_of_week
)
GROUP BY p.day_of_week, p.slot_date, p.slot_time
ORDER BY p.day_of_week ASC, p.slot_time ASC;
Another problem: if today is day_of_week = 5, but the next available day_of_week for a given lawyer is 2, how can I query that?
How to return the next closest and available day_of_week and aggregate to just return times from this day, not all days?
One possible solution
One thing I came with was to create 3 tables instead of one:
default_slots: 3 columns: lawyer_id, day_of_week, time
slots: laywer_id, day_of_week, time, date, status
appointments: all info regarding a booked appointment
Then I'll store ALL free time slots for every day of the actual date up to an year in the slots table for every lawyer. (taken time slots from default_slots).
+-----------+-------------+-----------+-----------+-----------+
| lawyer_id | day_of_week | slot_time | slot_date | status |
+-----------+-------------+-----------+-----------+-----------+
| 1 | 1 | 16:00 | 12/03/13 | 0 |
| 1 | 1 | 16:00 | 12/03/13 | 0 |
| 1 | 2 | 08:00 | 13/03/13 | 0 |
| 1 | 2 | 09:00 | 13/03/13 | 0 |
... next week
| 1 | 1 | 16:00 | 19/03/13 | 0 |
| 1 | 1 | 16:00 | 19/03/13 | 0 |
| 1 | 2 | 08:00 | 20/03/13 | 0 |
| 1 | 2 | 09:00 | 20/03/13 | 0 |
... up to an year
| 1 | 1 | 16:00 | 20/03/14 | 0 |
| 1 | 1 | 16:00 | 20/03/14 | 0 |
| 1 | 2 | 08:00 | 21/03/14 | 0 |
| 1 | 2 | 09:00 | 21/03/14 | 0 |
+-----------+-------------+-----------+-----------+-----------+
I'll also have some cron jobs that run every week that adds another week of free slot records in the table slots and also remove past records to reduce table size and unused data.
A lawyer will also be able to lock a time directly into slots, as well add specific times (point 2).
For the listing, it will be a matter of getting the slots for a date equal or greater than today with free times, since every time of every date will have a row.
Implications on this solution:
1) Day one we will have 2500 lawyers (2nd month around 6000). Assuming 8 possible slots/daily X 20 days of work/month X 12 months = 1920 slot records per lawyer.
2500 laywers x 1920 records = 4,8 million records on day one. (~12M the second month)
Those records will be UPDATED, INSERTED and DELETED all the time. The slots table has some indexes, so I can't imagine write operations being made constantly on a table with 12M+ records and some indexes. Indexes being updated every second doesn't see smart to me.
I really can't come with a reasonable and scalable solution. My solution with one table only could work, but I can't think in a way of querying that at all.
And the denormalized slots table will be huge, while needing constant write operations.
Any tips?
I have done something similar to what your trying to do so I understand how complicated it is :)
This was done in MSSQL so you will need to convert it to MySql.
These are the tables we ended up with:
TimeSlots:
We store both the default timesslots & modified timeslots for each staff member in this table (We have a column called "SlotType" in this table. SlotType 1 = DEFAULT TIMESLOTS & SlotType 2 = MODIFIED TIMESLOTS). If you look at "Tue 30/04/13" in the picture above you will see that we modified the timeslots for that day to only display a 9am appointment for this particular staff member.
ClosedDays:
This is a list of closed days - for example a staff member my not work on his birthday & Christmas day.
Appointments:
This is a list of appointments that have been booked (or waiting for booking confirmation).
SQL Query to get available appointments:
To check to appointments we then used the following SQL in our stored procedure. It checks one staff members appointments for the date specified. The final stored procedure that we are using loops though each staff member on the page for each day of the week to get all the appointments. Using this query to get 10 staff members appointments for the next 7 days = a total of 70 query's & takes about 300ms with a million records in each table. We are loading the appointments via ajax so 300ms is acceptable for our use & will prob change it to get each staff members appointments separately via ajax (so 7 query's at a time) to improve performance even more in the future.
DECLARE #MyDate date, #MyDayName nvarchar(10);
IF #StartDate IS NULL
SET #StartDate = GETDATE();
SET #MyDate = CAST(#StartDate AS date);
SET #MyDayName = DATENAME(dw, #MyDate );
--NOTES:
--#SlotType = 1 (DEFAULT TIMESLOTS), 2 (MODIFIED TIMESLOTS)
--***CHECK TO SEE IF DOCTOR IS CLOSED TODAY***
IF NOT EXISTS (SELECT [ClosedDays].[ID] FROM [ClosedDays] WHERE [ClosedDays].[StaffID] = #StaffID AND [ClosedDays].[BusinessID] = #BusinessID AND [ClosedDays].[Active] = 1 AND #MyDate BETWEEN [ClosedDays].[StartDate] AND [ClosedDays].[EndDate])
BEGIN
--***THE DOCTOR IS NOT CLOSED TODAY SO GET THE AVAILABLE TIMESLOTS***
--***CHECK TO SEE IF DOCTOR IS HAS MODIED TIMESLOTS TODAY***
IF NOT EXISTS (SELECT [TimeSlots].[ID], #MyDate AS SlotDate FROM [TimeSlots] WHERE [TimeSlots].[StaffID] = #StaffID AND [TimeSlots].[BusinessID] = #BusinessID AND [TimeSlots].[Active] = 1 AND [TimeSlots].[SlotType] = 2 AND [TimeSlots].[SlotDay] = #MyDayName AND #MyDate BETWEEN [TimeSlots].[StartDate] AND [TimeSlots].[EndDate] AND [TimeSlots].[ID] NOT IN (SELECT [Appointments].[TimeSlotID] FROM [Appointments]) )
BEGIN
--***THE DOCTOR HAS NO MODIFIED TIMESLOTS FOR TODAY USE THE DEFAULT ONES***
SELECT [TimeSlots].[ID] AS SlotID, [TimeSlots].[StaffID], [TimeSlots].[BusinessID], CONVERT(nvarchar(10), #MyDate, 103) AS SlotDate, [TimeSlots].[SlotDay], LTRIM(RIGHT(CONVERT(nvarchar(10), [TimeSlots].[SlotTime], 100), 7))AS SlotTime FROM [TimeSlots]
WHERE [TimeSlots].[StaffID] = #StaffID AND [TimeSlots].[BusinessID] = #BusinessID AND [TimeSlots].[Active] = 1 AND [TimeSlots].[SlotType] = 1 AND [TimeSlots].[SlotDay] = #MyDayName AND #MyDate BETWEEN [TimeSlots].[StartDate] AND [TimeSlots].[EndDate] AND NOT EXISTS (SELECT [Appointments].[TimeSlotID] FROM [Appointments] WHERE [Appointments].[TimeSlotID] = [TimeSlots].[ID])
END
ELSE
BEGIN
--***THE DOCTOR HAS MODIFIED TODAYS TIMESLOTS SO USE THE MODIFIED TIMESLOTS***
SELECT [TimeSlots].[ID] AS SlotID, [TimeSlots].[StaffID], [TimeSlots].[BusinessID], CONVERT(nvarchar(10), #MyDate, 103) AS SlotDate, [TimeSlots].[SlotDay], LTRIM(RIGHT(CONVERT(nvarchar(10), [TimeSlots].[SlotTime], 100), 7))AS SlotTime FROM [TimeSlots]
WHERE [TimeSlots].[StaffID] = #StaffID AND [TimeSlots].[BusinessID] = #BusinessID AND [TimeSlots].[Active] = 1 AND [TimeSlots].[SlotType] = 2 AND [TimeSlots].[SlotDay] = #MyDayName AND #MyDate BETWEEN [TimeSlots].[StartDate] AND [TimeSlots].[EndDate] AND NOT EXISTS (SELECT [Appointments].[TimeSlotID] FROM [Appointments] WHERE [Appointments].[TimeSlotID] = [TimeSlots].[ID])
END
END
ELSE
BEGIN
--***NO APPOINTMENTS WERE FOUND***
--***DUMMY QUERY TO RETURN NO RECORDS***
SELECT [TimeSlots].[ID] AS SlotID, [TimeSlots].[StaffID], [TimeSlots].[BusinessID], CONVERT(nvarchar(10), #MyDate, 103) AS SlotDate, [TimeSlots].[SlotDay], LTRIM(RIGHT(CONVERT(nvarchar(10), [TimeSlots].[SlotTime], 100), 7))AS SlotTime FROM [TimeSlots]
WHERE [TimeSlots].[ID] = -0
END
Hope this makes sense & if anyone else has some idea's on how to optimize this more please let me know!
You're right that you'll have a big table. But it's not clear that your application will fail as a result. MySQL (and all DBMS software) is made to allow the accessing of large tables quickly.
Good dedicated MySQL server hardware (which has a 64-bit OS, two or four fast processors, plenty of RAM, and excellent file I/O -- SAS-interfaced fast disks) and properly configured server software will handle this workload.
You may wish to merge slot_time and slot_date into a single DATETIME or TIMESTAMP field, that can be indexed for ease of searching. If you choose to use TIMESTAMP data items you'll get some nice timezone-handling benefits if you do things right.
You may want to work out how to partition your big table using a scheme that lets you take a month's worth, or even a week's worth, of data offline when that month or week is past.
With 2,500 lawyers using your system, you're going to want to get this right. Why not spend some money on a decent database administrator? They cost less per hour than most lawyers. Sheeri Cabral wrote up a good summary of how to find one. http://www.sheeri.org/how-to-find-a-dba/
I have a table that is going to have several time stamp entries added throughout the day with a specific employee ID tied to each entry. I am curious how I would get the first timestamp of the day and the last time stamp of the day to calculate amount of time worked for that specific employee on the specific date. My table is below:
+----+------------+----------+---------+---------------------+-----------+------------+-----------+---------+
| id | employeeID | date | timeIn | jobDescription | equipType | unitNumber | unitHours | timeOut |
+----+------------+----------+---------+---------------------+-----------+------------+-----------+---------+
| 1 | 1 | 01/13/13 | 8:17 pm | Worked in Hubbard | Dozer | 2D | 11931 | 8:17 pm |
| 2 | 1 | 01/13/13 | 8:17 pm | Worked in Jefferson | Excavator | 01E | 8341 | 8:18 pm |
+----+------------+----------+---------+---------------------+-----------+------------+-----------+---------+
so far I have a query like this to retrieve the time values:
$stmt = $conn->prepare('SELECT * FROM `timeRecords` WHERE `date`= :dateToday AND `employeeID` = :employeeID ORDER BY employeeID ASC');
$stmt->execute(array(':employeeID' => $_SESSION['employeeID'], ':dateToday' => $dateToday));
But I am unsure of how to obtain the greatest value in the timeOut column
Really, you just need the aggregate MAX() and MIN() grouped by employeeID. Use the TIMEDIFF() function to calculate the difference in time between the two.
SELECT
`employeeID`,
MIN(`timeIn`) AS `timeIn`,
MAX(`timeOut`) AS `timeOut`,
TIMEDIFF(MAX(`timeOut`), MIN(`timeIn`)) AS `totalTime`
FROM `timeRecords`
WHERE
`date` = :dateToday
AND `employeeID` = :employeeID
/* Selecting only one employeeID you don't actually need the GROUP BY */
GROUP BY `employeeID`
However, this won't report the total time worked if an employee clocks in and out several times during one day. In that case, you would need to SUM() the result of the TIMEDIFF() for each of the in/out pairs.
Something like:
SELECT
`employeeID`,
/* Assumes no times overlap across rows */
SEC_TO_TIME(SUM(TIME_TO_SEC(TIMEDIFF(`timeOut`, `timeIn`)))) AS `totalTime`
FROM `timeRecords`
WHERE
`date` = :dateToday
AND `employeeID` = :employeeID
GROUP BY `employeeID`