Рассмотрим следующий, очень упрощенный пример:
DROP TABLE IF EXISTS slots;
CREATE TABLE slots
(id SERIAL PRIMARY KEY,slot VARCHAR(12) NOT NULL UNIQUE);;
INSERT INTO slots VALUES
(1,'Slot 1'),
(2,'Slot 2'),
(3,'Slot 3'),
(4,'Slot 4'),
(5,'Slot 5');
DROP TABLE IF EXISTS bookings;
CREATE TABLE bookings
(booking_id SERIAL PRIMARY KEY
,user_id INT NOT NULL
,slot_id INT NOT NULL UNIQUE
);
INSERT INTO bookings VALUES
(1,101,3);
Чтобы показать доступные слоты, мы можем сделать что-то вроде этого ...
SELECT s.*
FROM slots s
LEFT
JOIN bookings b
ON b.slot_id = s.id
WHERE b.booking_id IS NULL;
+----+--------+
| id | slot |
+----+--------+
| 1 | Slot 1 |
| 2 | Slot 2 |
| 4 | Slot 4 |
| 5 | Slot 5 |
+----+--------+
... или это ...
SELECT s.*
, CASE WHEN b.booking_id IS NULL THEN 'yes' ELSE 'no' END available
FROM slots s
LEFT
JOIN bookings b
ON b.slot_id = s.id;
+----+--------+-----------+
| id | slot | available |
+----+--------+-----------+
| 1 | Slot 1 | yes |
| 2 | Slot 2 | yes |
| 3 | Slot 3 | no |
| 4 | Slot 4 | yes |
| 5 | Slot 5 | yes |
+----+--------+-----------+
Чтобы убедиться, что два пользователя не могут забронировать один и тот же слот одновременно, мы можем сделать что-то вроде этого ...
INSERT INTO bookings (user_id,slot_id)
SELECT 102,1
FROM (SELECT 1) x
LEFT
JOIN bookings y
ON y.slot_id = 1
WHERE y.booking_id IS NULL;
SELECT * FROM bookings;
+------------+---------+---------+
| booking_id | user_id | slot_id |
+------------+---------+---------+
| 1 | 101 | 3 |
| 2 | 102 | 1 |
+------------+---------+---------+
..., что предотвращает бронирование другого пользователятот же слот ...
INSERT INTO bookings (user_id,slot_id)
SELECT 103,1
FROM (SELECT 1) x
LEFT
JOIN bookings y
ON y.slot_id = 1
WHERE y.booking_id IS NULL;
SELECT * FROM bookings;
+------------+---------+---------+
| booking_id | user_id | slot_id |
+------------+---------+---------+
| 1 | 101 | 3 |
| 2 | 102 | 1 |
+------------+---------+---------+
Все остальное может быть обработано в коде вашего приложения (PHP).