MySQL dynamically find available reservations - php

I have a requirement to create a room reservation system with dynamic booking slots (a reservation can start at any time and last anywhere from 15 minutes up to several days), but I can't crack the logic.
Reservations need to consider the opening times of the rooms (some rooms are based at sites that are available for 24 hours and others only a few hours per day. Some days, rooms may be entirely unavailable or have reduced opening hours). A reservation cannot jump across opening times with a gap greater than 1 second. For example, it is ok for a reservation to be accepted if the closing time on Sunday is 23:59:59 and it reopens at 00:00:00 on Monday, as this isn't considered a gap. However, if the opening time were 01:00:00 Monday, this would not be acceptable.
In addition, the database will have rooms across the world, operating in different time zones, so this will also need to be a consideration in the final design. Finally, a reservation cannot begin or end within 1 hour of another reservation.
Here is a stripped back schema of our current tables:
site
+---------------------------------------+-------+------------------------+---------------------------------------+
| uuid | id | name | address |
+---------------------------------------+-------+------------------------+---------------------------------------+
| 418bbdcb-09c9-4407-adb4-162fb3e5e6f3 | 1 | NAMCO Library | 6 London Rd, Los Angeles, USA, 087098 |
+---------------------------------------+-------+------------------------+---------------------------------------+
| 418bbdcb-09c9-4407-adb4-162fb3e5e6f6 | 2 | Livingston Hotel | 6 Jump Street, London, UK, E56JK |
+---------------------------------------+-------+------------------------+---------------------------------------+
opening_times
+----+----------+--------------+-----------+-------------+---------------+-----------------------+
| id | site_id | day_of_week | open | close | date_outlier | timezone |
+----+----------+--------------+-----------+-------------+---------------+-----------------------+
| 1 | 1 | 1 | 10:00:00 | 15:59:59 | NULL | America/Los_Angeles |
+----+----------+--------------+-----------+-------------+---------------+-----------------------+
| 2 | 1 | 2 | 07:00:00 | 21:59:59 | NULL | America/Los_Angeles |
+----+----------+--------------+-----------+-------------+---------------+-----------------------+
| 3 | 1 | 3 | 07:00:00 | 21:59:59 | NULL | America/Los_Angeles |
+----+----------+--------------+-----------+-------------+---------------+-----------------------+
| 4 | 1 | 4 | 07:00:00 | 21:59:59 | NULL | America/Los_Angeles |
+----+----------+--------------+-----------+-------------+---------------+-----------------------+
| 5 | 1 | 5 | 07:00:00 | 21:59:59 | NULL | America/Los_Angeles |
+----+----------+--------------+-----------+-------------+---------------+-----------------------+
| 6 | 1 | 6 | 07:00:00 | 21:59:59 | NULL | America/Los_Angeles |
+----+----------+--------------+-----------+-------------+---------------+-----------------------+
| 7 | 1 | 7 | 10:00:00 | 22:59:59 | NULL | America/Los_Angeles |
+----+----------+--------------+-----------+-------------+---------------+-----------------------+
| 8 | 2 | 1 | 00:00:00 | 23:59:59 | NULL | Europe/London |
+----+----------+--------------+-----------+-------------+---------------+-----------------------+
| 9 | 2 | 2 | 00:00:00 | 23:59:59 | NULL | Europe/London |
+----+----------+--------------+-----------+-------------+---------------+-----------------------+
| 10 | 2 | 3 | 00:00:00 | 23:59:59 | NULL | Europe/London |
+----+----------+--------------+-----------+-------------+---------------+-----------------------+
| 11 | 2 | 4 | 00:00:00 | 23:59:59 | NULL | Europe/London |
+----+----------+--------------+-----------+-------------+---------------+-----------------------+
| 12 | 2 | 5 | 00:00:00 | 23:59:59 | NULL | Europe/London |
+----+----------+--------------+-----------+-------------+---------------+-----------------------+
| 13 | 2 | 6 | 00:00:00 | 23:59:59 | NULL | Europe/London |
+----+----------+--------------+-----------+-------------+---------------+-----------------------+
| 14 | 2 | 7 | 00:00:00 | 23:59:59 | NULL | Europe/London |
+----+----------+--------------+-----------+-------------+---------------+-----------------------+
| 15 | 2 | NULL | 10:30:00 | 16:59:59 | 2022-05-04 | Europe/London |
+----+----------+--------------+-----------+-------------+---------------+-----------------------+
| 16 | 2 | NULL | NULL | NULL | 2022-05-05 | Europe/London |
+----+----------+--------------+-----------+-------------+---------------+-----------------------+
All times in this table are in local timezones.
Row 15 on this table shows a reduced opening time at the Livingston Hotel on May 4th, 2022.
Row 16 on this table shows that the Livingston Hotel does not allow any bookings on May 5th, 2022.
rooms
+---------------------------------------+-------+---------+------------------------+-------------+-----------+
| uuid | id | site_id | name | hourly_cost | currency |
+---------------------------------------+-------+---------+------------------------+-------------+-----------+
| 418bbdcb-09c9-4407-adb4-162fb3e5e6d3 | 1 | 1 | Blue Room | 60.00 | USD |
+---------------------------------------+-------+---------+------------------------+-------------+-----------+
| 418bbdcb-09c9-4407-adb4-162fb3e5e6d6 | 2 | 1 | Red Room | 35.50 | USD |
+---------------------------------------+-------+---------+------------------------+-------------+-----------+
| 418bbdcb-09c9-4407-adb4-162fb3e5e6d7 | 3 | 1 | Purple Room | 15.50 | USD |
+---------------------------------------+-------+---------+------------------------+-------------+-----------+
| 418bbdcb-09c9-4407-adb4-162fb3e5e6d8 | 4 | 2 | Dragon Room | 55.50 | GBP |
+---------------------------------------+-------+---------+------------------------+-------------+-----------+
| 418bbdcb-09c9-4407-adb4-162fb3e5e6d9 | 5 | 2 | Bus Room | 85.00 | GBP |
+---------------------------------------+-------+---------+------------------------+-------------+-----------+
reservations
+---------------------------------------+---------+-------------+----------------------+---------------------+--------------+
| uuid | room_id | customer_id | start | end | cancelled_at |
+---------------------------------------+---------+-------------+----------------------+---------------------+--------------+
| 418bbdcb-09c9-4407-adb4-162fb3e5e6h3 | 3 | 1 | 2022-05-04 14:01:53 | 2022-05-01 14:16:53 | NULL |
+---------------------------------------+---------+-------------+----------------------+---------------------+--------------+
| 418bbdcb-09c9-4407-adb4-162fb3e5e6h4 | 4 | 3 | 2022-05-03 11:01:53 | 2022-05-03 12:01:53 | NULL |
+---------------------------------------+---------+-------------+----------------------+---------------------+--------------+
Start and end times in this table are stored in UTC.
The SQL that we currently use does not correctly deal with reservations spanning different days and has no consideration of timezone conversions for opening times.
We're using prepared statements to replace the following strings in the SQL.
:start is the start time of the reservation in UTC
:end is the end time of the reservation in UTC
SELECT
sites.id site_id,
sites.site_ref,
sites.name site_name,
rooms.name room_name,
FROM
sites
JOIN
rooms
ON
rooms.site_id = sites.id
LEFT JOIN
reservations bookings
ON
rooms.id = reservations.room_id
AND (
(:start + INTERVAL 1 HOUR) <= reservations.end
AND
(:end - INTERVAL 1 HOUR) >= reservations.start
AND
reservations.cancelled_at IS NULL
)
JOIN
opening_times
ON
sites.id = opening_times.site_id
AND (
opening_times.site_id NOT IN (
SELECT
site_id
FROM
tbl_opening_times
WHERE
DATE(:start) = date_outlier AND open IS NULL AND close IS NULL
) OR (
(DATE(:start) = opening_times.date_outlier AND TIME(:start) >= opening_times.open AND TIME(:end) <= opening_times.close)
OR
(DAYOFWEEK(DATE(:start)) = opening_times.dow AND TIME(:start) >= opening_times.open AND TIME(:end) <= opening_times.close)
)
)
WHERE
reservations.uuid IS NULL
ORDER BY
sites.id
Tests
A query for a reservation lasting 3 hours starting at 2022-05-04 14:00:00 (UTC) should list room id 1,2 at NAMCO Library. The rooms at the Livingston Hotel should not be listed as the end of the reservation will happen after the particular closing time of the hotel.
A query for a reservation lasting two days starting at 2022-05-01 12:30:00 (UTC) should list room id five at Livingston Hotel.
A query for a reservation lasting 40 minutes starting at 2022-05-05 15:30:00 (UTC) should list room id 1,2,3 at NAMCO Library.
I'm open to solutions that involve processing on the application side (we use PHP) if the complexity is too much for MySQL alone.
FYI we're using MySQL 8.*

Related

mySQL group_concat max dates based on other column

I have input table:
+-----+------------+---------------------+---------+-------------+
| id | client_id | subscription_date | program |how_long_subs|
+-----+------------+---------------------+---------+-------------+
| 1 | 1 | 2016-05-20 00:00:00 | W90 | 12 |
| 2 | 4 | 2017-01-01 00:00:00 | W90 | 6 |
| 314 | 7 | 2017-03-21 00:00:00 | AB | 12 |
| 3 | 8 | 2016-12-19 00:00:00 | W90 | 12 |
| 4 | 9 | 2018-06-08 00:00:00 | W90 | 12 |
| 5 | 10 | 2017-06-12 00:00:00 | W90 | 12 |
| 313 | 10 | 2017-01-18 00:00:00 | AB | 12 |
| 377 | 11 | 2018-12-22 00:00:00 | AB | 12 |
| 308 | 11 | 2017-12-22 00:00:00 | AB | 12 |
| 6 | 11 | 2017-12-22 00:00:00 | W90 | 12 |
| 7 | 13 | 2017-01-05 00:00:00 | W90 | 6 |
| 8 | 21 | 2017-03-10 00:00:00 | W90 | 12 |
| 325 | 22 | 2017-03-02 00:00:00 | AB | 1 |
+-----+------------+---------------------+---------+-------------+
id is unique autoincremented column for this table client_id is to connect with clients table. I am looking for a result in form:
+------------+----------+-----------------------------------------+--------+
| client_id | programs | dates |how_long|
+------------+----------+-----------------------------------------+--------+
| 1 | W90 | 2016-05-20 00:00:00 | 12 |
| ... | | | |
| 11 | W90|AB | 2017-12-22 00:00:00|2018-12-22 00:00:00 | 12|12 |
+------------+----------+-----------------------------------------+--------+
so every client_id has 3 columns: programs, dates, how_long
so far I have below for columns programy and na_ile
SELECT
client_id,
GROUP_CONCAT(DISTINCT program SEPARATOR '|') AS programs
FROM subscriptions GROUP BY client_id
but I have no idea how to do this for dates, so everything is in good order.
in example result I chose some client that has multiple rows for different programs, to best illustrate, as you can see dates in result are MAX date for certain program.
To give you better picture what I'm trying to do is process my input table, to be able to calculate remaining subscription for different programs.
Formula is:
if client_id has no records in subscriptions then use date from clients table
and return difference between that date +1 year and today.
if client_id has records in subscriptions then
for every unique program client has in subs table:
get max subscription_date and corresponding how_long_subs for that max date/program. add how_long_subs months to subscription date and return difference from now in days.
My plan is to get result table as described above and use php to process rows to get something like this:
example result for client_id: 11
W90: 2017-12-22 00:00:00 +12 months - now()
AB: 2018-12-22 00:00:00 +12 months - now()
Can you please help me with mySQL query and advice if approach im taking is ok or maybe there is some much easier way of doing it.
Thank you
SELECT A.client_id,
GROUP_CONCAT(DISTINCT A.program SEPARATOR '|') programs,
GROUP_CONCAT(DISTINCT A.subscription_date SEPARATOR '|') dates,
GROUP_CONCAT(A.how_long_subs SEPARATOR '|') how_long
FROM
(SELECT client_id, subscription_date, MAX(program) program, how_long_subs
FROM subscriptions
GROUP BY client_id, subscription_date,how_long_subs) A
GROUP BY A.client_id;
See DEMO on SQL Fiddle.
You could use a subquery for get the max date
SELECT client_id, GROUP_CONCAT( program SEPARATOR '|') programs,
GROUP_CONCAT(max_date SEPARATOR '|') max_date
FROM (
SELECT
client_id,
programs,
max(subscription_date) max_date
FROM subscriptions
GROUP BY client_id, program )

SQL request for several tables and operations in MySQL

I have the following 3 tables: unit, stage, stats.
unit stage
+----+--------+ +----+-------+---------------------+
| id | status | | id |unit_id| date |
+----+--------+ +----+-------+---------------------+
| 1 | 2 | | 1 | 2 | 2013-11-22 00:00:00 |
| 2 | 3 | | 2 | 2 | 2013-11-26 12:00:00 |
| 3 | 3 | | 3 | 3 | 2013-10-11 00:00:00 |
| 4 | 0 | | 4 | 1 | 2013-12-29 00:00:00 |
+----+--------+ +----+-------+---------------------+
stats
+----+----------+---------------------+-------+
| id | stage_id | date | clicks|
+----+----------+---------------------+-------+
| 1 | 1 | 2013-11-22 00:00:00 | 10 |
| 2 | 1 | 2013-11-23 00:00:00 | 20 |
| 3 | 1 | 2013-11-24 00:00:00 | 25 |
| 4 | 2 | 2013-11-26 00:00:00 | 15 |
| 5 | 2 | 2013-11-27 12:00:00 | 21 |
| 6 | 3 | 2013-12-29 00:00:00 | 8 |
+----+----------+---------------------+-------+
I need a request, that will produce the following response:
+---------+---------------------+-----------------------+
| unit.id | stage.min.date | sum(stats.max.clicks) |
+---------+---------------------+-----------------------+
| 2 | 2013-11-22 00:00:00 | 46 |
| 3 | 2013-12-29 00:00:00 | 8 |
+---------+---------------------+-----------------------+
by the following rules:
1) unit.id - show only units with unit.status=3
2) stage.min.date - minimal stage.date for corresponding unit_id
3) sum(stats.max.clicks) - sum of stats.clicks with max dvalues for each stage_id associated with corresponding unit_id. In my example 46 = 25(stage_id=1) + 21(stage_id=2)
The problem is in min.date and sum of clicks - I have no idea how to get it in one query. Definitely it`s not a problem to do it using php code and several requests.
Schema in SQL Fiddle
Thanks in advance.
I just ask myself, why I do this? Your example resonse has an error, and does not match your fiddle... but:
SELECT
cc.unit_id, MIN(cc.date) as stage_min_date , SUM(dd.clicks) as stats_max_clicks
FROM
stage cc
LEFT JOIN (
SELECT
bb.stage_id, bb.clicks
FROM
stats bb LEFT JOIN (
SELECT id, stage_id, MAX(date) AS max_date
FROM stats
GROUP BY stage_id
) aa
ON
aa.max_date = bb.date
WHERE
aa.max_date IS NOT NULL
) dd
ON cc.id = dd.stage_id
LEFT JOIN unit ee
ON ee.id = cc.unit_id
WHERE ee.status = 3
GROUP BY cc.unit_id
...

Selecting rows with max value in range

I have the followng data:
+----+---------+---------------------+-------+
| id | site_id | datetime | views |
+----+---------+---------------------+-------+
| 1 | 1 | 2013-11-01 23:59:59 | 12 |
| 2 | 1 | 2013-11-02 23:59:59 | 15 |
| 3 | 1 | 2013-11-03 23:59:59 | 18 |
| 4 | 1 | 2013-11-04 23:59:59 | 29 |
| 5 | 1 | 2013-11-05 23:59:59 | 38 |
| 6 | 1 | 2013-11-05 12:59:59 | 40 |
| 7 | 1 | 2013-11-06 23:59:59 | 45 |
| 8 | 1 | 2013-11-07 23:59:59 | 49 |
| 9 | 1 | 2013-11-08 23:59:59 | 52 |
| 10 | 2 | 2013-11-04 23:59:59 | 25 |
| 11 | 2 | 2013-11-05 21:59:59 | 42 |
| 12 | 2 | 2013-11-06 23:59:59 | 60 |
| 13 | 2 | 2013-11-07 23:59:59 | 75 |
| 14 | 2 | 2013-11-08 23:59:59 | 86 |
| 15 | 2 | 2013-11-09 23:59:59 | 90 |
| 16 | 2 | 2013-11-10 23:59:59 | 92 |
| 17 | 2 | 2013-11-11 23:42:59 | 98 |
+----+---------+---------------------+-------+
I would pass a day and wish to get the rows with the highest time in the given day or if there`s no records for this site for this day, the last available row in the past.
e.g. for 2013-11-01
+----+---------+---------------------+-------+
| id | site_id | datetime | views |
+----+---------+---------------------+-------+
| 1 | 1 | 2013-11-01 23:59:59 | 12 |
+----+---------+---------------------+-------+
for 2013-11-05
+----+---------+---------------------+-------+
| id | site_id | datetime | views |
+----+---------+---------------------+-------+
| 5 | 1 | 2013-11-05 23:59:59 | 38 |
| 11 | 2 | 2013-11-05 21:59:59 | 42 |
+----+---------+---------------------+-------+
and for 2013-11-10
+----+---------+---------------------+-------+
| id | site_id | datetime | views |
+----+---------+---------------------+-------+
| 9 | 1 | 2013-11-08 23:59:59 | 52 |
| 16 | 2 | 2013-11-10 23:59:59 | 92 |
+----+---------+---------------------+-------+
Thanks in advance.
You can try this:
SELECT a.id,a.site_id,b.maxDate,a.views
FROM table1 a
INNER JOIN (
SELECT site_id ,MAX(datetime) as maxDate
FROM table1
WHERE datetime < DATEYOUWANTTOSEE + INTERVAL 1 DAY
GROUP BY site_id
) b ON a.site_id = b.site_id AND a.datetime = b.maxDate
The inner query will get you the MAX(datetime) for each site_id. Then you join it with your table to get the rest of the information.
sqlfiddle demo
SELECT * FROM <tablename> WHERE datetime = <datetime> ORDER BY datetime DESC LIMIT 2
You data and examples do not really match themselves, nor the description, but what you probably are looking for is this:
Select top 1 *
from table
where date(datetime) <= date(#PARAMETER)
order by datetime desc
I believe this should work:
SELECT SUBSTRING(`datetime`, 1, 10) AS date, MAX(`views`)
FROM table
GROUP BY SUBSTRING(`datetime`, 1, 10)
If you need the id/site_id as well, write it in your post, as it is not clear
SQLFiddle to show you the result:
http://sqlfiddle.com/#!2/e0ccb3/1

How to summ total amount of equipments in given date ranges [duplicate]

This question already has an answer here:
Closed 10 years ago.
Possible Duplicate:
Calculating total quantity of equipments for a date range
Project: I am working on a project which is about some rooms and equipments using in the rooms. The software is about scheduling the equipments in the rooms. In other words, it is a reservation software that reserves selected equipments in separate rooms for needed dates and times ranges. I have many tables in MYsSQL database working with Php but I will mention the tables my question is about. The tables I will relate my questions are equipment table (Table A), schedule table (Table B) and equipments using in the related schedule (Table C).
Table A: equipment list table
+------+----------+-----------+
| eqid | eqName | available |
+------+----------+-----------+
| 1 | book | 90 |
| 2 | pen | 82 |
| 3 | computer | 25 |
+------+----------+-----------+
In table A; eqid represents unique id of an equipment, eqName represents name of an equipment, available represents total available equipments existing.
Table B: schedule table
+------------+------------+------------+-----------+----------+--------+
| scheduleid | startDate | endDate | startTime | endTime | office |
+------------+------------+------------+-----------+----------+--------+
| 1 | 2012-08-27 | 2012-08-27 | 08:30:00 | 10:00:00 | room1 |
| 2 | 2012-08-27 | 2012-08-27 | 09:30:00 | 11:00:00 | room3 |
| 3 | 2012-08-28 | 2012-08-30 | 08:30:00 | 12:00:00 | room2 |
| 4 | 2012-08-29 | 2012-08-31 | 11:30:00 | 14:00:00 | room1 |
| 5 | 2012-08-28 | 2012-08-28 | 10:30:00 | 14:00:00 | room3 |
| 6 | 2012-08-27 | 2012-08-30 | 08:30:00 | 10:00:00 | room4 |
| 7 | 2012-08-27 | 2012-08-27 | 10:30:00 | 12:00:00 | room4 |
| 8 | 2012-08-27 | 2012-08-30 | 08:30:00 | 11:00:00 | room6 |
| 9 | 2012-08-27 | 2012-08-27 | 10:30:00 | 12:00:00 | room5 |
+------------+------------+------------+-----------+----------+--------+
In table B; scheduleid represents unique id for a schedule, startDate and endDate are date range for a schedule, startTime and endTime time range for a schedule, office means that where the schedule will take place. Let me give an example here. Scheduleid 1 means there is a reservation on 27th of august 2012, Monday and it is from 08.30 to 10:00. As it start and end on same day this is just one day reservation in room1. However, Scheduleid 3 means there is a reservation starts on 28th of august 2012, Tuesday and goes on until 30th of august 2012, Thursday at 08:30-12:00... in other words, it lasts for 3 days and everyday from 08:30 to 12:00... So there is a reservation from Tuesday to Thursday at 08:30 to 12:00 in room2... I hope this is clear.
Table C: equipments using in the related schedule
+--------+------------+------+-------------+
| Autoid | scheduleid | eqid | amountInSch |
+--------+------------+------+-------------+
| 1 | 1 | 1 | 2 |
| 2 | 1 | 2 | 3 |
| 3 | 1 | 3 | 1 |
| 4 | 2 | 1 | 1 |
| 5 | 2 | 2 | 1 |
| 6 | 2 | 3 | 2 |
| 7 | 3 | 2 | 1 |
| 8 | 3 | 3 | 3 |
| 9 | 4 | 2 | 1 |
| 10 | 4 | 3 | 1 |
| 11 | 5 | 1 | 1 |
| 12 | 6 | 1 | 1 |
| 13 | 6 | 3 | 2 |
| 14 | 6 | 2 | 4 |
| 15 | 7 | 1 | 5 |
| 16 | 7 | 2 | 6 |
| 17 | 8 | 2 | 1 |
| 18 | 9 | 1 | 8 |
| 19 | 9 | 2 | 5 |
| 20 | 9 | 3 | 6 |
+--------+------------+------+-------------+
In table C: Autoid represents unique automatic id generated by auto-increment, scheduleid comes from Table B, eqid comes from Table A, amountInSch represents how many (amount) equipment will use in the related schedule. I want to give an example here. Scheduleid 1 in Table C, there are 3 rows. This means that scheduleid 1 related in TAble B will use 2 books (eqid 1), 3 pens (eqid 2) and 1 computer (eqid 3) in room1 specified dates and times in table B . Another example is that scheduleid 3 in Table C is related 2 rows. It means that 1 pen (eqId 2) and 3 computers (eqId 3) will be using in room2 from 27th to 30th of august 2012 everyday from 08:30 to 12:00.
The above is the explanation and give some information about the project. The table rows are not permanent. When you make a reservation, there will be a new row in Table B and if it is selected an equipment, there will be new rows in table C...
The Question:
I want to calculate left amount of a specific equipment when I supply eqId, startDate, endDate, startTime and endTime...
An example:
eqId: 1 (book)
startDate: 2012-08-27
endDate: 2012-08-27
startTime: 08:30:00
endTime: 12:00:00
Result should be: 14 books used in schedule and 76 left available books
Because: if you look scheduleIds and related eqIds, you will only see 1, 2, 6, 7, 9 scheduleIds related to my query(dates and eqId). If you sum the all amount of related in Table C, you will get the wrong result. In other words, related amounts for eqId(1-book) and for 1, 2, 6, 7, 9 scheduleIds are 2, 1, 1, 5, 8 respectively. So if you sum them you will get 17 which is wrong. Because, 1 and 9 schedule don't intersect each other in terms of start and end Times, and 6 and 7 don't intersect each other either. as a result of them 2 stays lonely and can be count separately. We must consider 1 and 9 as summed 8 because 8 is bigger than 2. it is same for 6 and 7, considered as 5 because of 5 is bigger than 1...
So folks! I am not sure how I can sum/ this in programming algorithm. Is there a way to do in SQL or do I have to use PHP and Mysql together? and How?
SQLFiddle Records
There are different ways of achieving this - I will point you at something that can be used with most DB-engines.
In mysql, it is possible to merge tables in a single query. What you need is something along the line of this:
$eqid = 1;
$startDate = "2012-08-27";
$endDate = "2012-08-27";
$startTime = "08:30:00";
$endTime = "12:00:00";
$sql = "SELECT SUM(`amountInSch`) FROM `table_c`,`table_b` WHERE `eqid` = $eqid
AND `startDate` >= '$startDate' AND `startDate` <= '$endDate' AND `endDate`
<= '$endDate' AND `endDate` >= '$startDate' AND `startTime` >= '$startTime'
AND `startTime` <= '$endTime' AND `endTime` <= '$endTime' AND `endTime` >=
'$startTime' AND `table_b`.`scheduleid` = `table_c`.`scheduleid`";
$r = mysql_query($sql);
$n = mysql_result($r,0,0);
The trick is to use the table_b`.`scheduleid` =
`table_c`.`scheduleid (some quotes are missing due to markup here) to merge the two tables.

How to find out if store open or close - dealing with hours?

What is the best way to store shop opening and closing time in the database and also how to calculate the time in PHP?
I have come up with this table design:
+----+---------+----------+-----------+------------+
| id | shop_id | week_day | open_hour | close_hour |
+----+---------+----------+-----------+------------+
| 1 | 3 | 1 | 15:00:00 | 23:00:00 |
| 2 | 3 | 2 | 15:00:00 | 23:00:00 |
| 3 | 3 | 3 | 18:00:00 | 02:00:00 |
| 4 | 3 | 4 | 18:00:00 | 02:00:00 |
| 5 | 3 | 5 | 18:00:00 | 03:00:00 |
+----+---------+----------+-----------+------------+
+------------+---------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+------------+---------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| shop_id | int(11) | NO | | NULL | |
| week_day | int(11) | NO | | NULL | |
| open_hour | time | NO | | NULL | |
| close_hour | time | NO | | NULL | |
+------------+---------+------+-----+---------+----------------+
For example, on Tuesday (week_day = 2) it open at 3PM and close at 11PM (Tuesday).
On Wednesday (`week_day = 2'), it open at 6PM and close after midnight at 2AM which would be Thursday. How should midnight (00:00:00 or after) closing time should be stored in the database?
Let say customer want to place an order (shop_id = 3) at 10PM on Tuesday, they should be able to do so according to the database data. However if customer want to place an order at 1AM on Thursday but the database show that week_day = 3 it close at 02:00:00
How to write in PHP to work out if the shop open or not? it seem complicated!
Do I need to change the the table design so it would much easier to write in PHP?
I guess you could do a SQL-question like this, and check if the query return any results:
SELECT * FROM opening_hours_table WHERE shop_id = your_shop_id AND week_day = WEEKDAY(NOW()) + 1 AND open_hour < NOW() AND close_hour > NOW()
If you get a result back, then your within opening hours.
Edit:
Made a few syntax-corrections to the SQL.
You can consider making the table information truly correct
+----+---------+----------+-----------+------------+
| id | shop_id | week_day | open_hour | close_hour |
+----+---------+----------+-----------+------------+
| 1 | 3 | 1 | 15:00:00 | 23:00:00 |
| 2 | 3 | 2 | 15:00:00 | 23:00:00 |
| 3 | 3 | 3 | 18:00:00 | 23:59:59 |
| 4 | 3 | 4 | 00:00:00 | 02:00:00 |
| 5 | 3 | 4 | 18:00:00 | 23:59:59 |
| 6 | 3 | 5 | 00:00:00 | 02:00:00 |
| 7 | 3 | 5 | 18:00:00 | 23:59:59 |
| 8 | 3 | 6 | 00:00:00 | 03:00:00 |
+----+---------+----------+-----------+------------+
Then use the following kind of (this query is for Tuesday 10:00PM as you mentioned):
SELECT count(*) FROM `shop`
WHERE week_day=3
and open_hour<='22:00:00'
and close_hour>='22:00:00'
As I can understand (and correct me if I'm not understanding) you should check if the time is between the open_hour and 23:59 of the current day, and between 00:00 and close_hour of the following day.
That should be done on the APP code and not on the Database.
IMHO, you're right with your DB design!

Categories