MySQL: можно ли создать запрос, оценивающий данные из разных записей?

У меня есть такая таблица. Он показывает время начала и окончания работы различных ресторанов в разные дни недели.

Нет Ресторан будний день Время начала Время окончания 1 А пн 10:00 21:00 2 А Вт 10:00 21:00 3 А Обвенчались 19:00 08:00 4 А Чт 5 А пт 10:00 21:00 6 А Сидел 10:00 21:00 7 А Солнце 19:00 08:00 8 Б пн 11:00 21:00 9 Б Вт 11:00 21:00 10 Б Обвенчались 11:00 23:00 11 Б Чт 11:00 23:00 12 Б пт 11:00 16:00 13 Б Сидел 10:00 00:00 14 Б Солнце 00:00 13:00

Я хочу вот что. Учитывая текущее время, код должен отображать, какой ресторан открыт в данный момент. Это то, что я пробовал.

(CASE WHEN user_time.start_time > user_time.end_time AND ( CURTIME() < user_time.end_time OR CURTIME() > user_time.start_time ) THEN 1
      WHEN user_time.start_time < user_time.end_time AND ( CURTIME() > user_time.start_time AND CURTIME() < user_time.end_time ) THEN 1
      ELSE 0
 END) = 0 AND user_time.weekday = WEEKDAY(CURDATE())

Он находит текущий день недели и соответствующее время открытия и окончания для сравнения с текущим временем. Но проблема возникает, когда ресторан открывается вечером и заканчивается на следующий день.

  1. В случае № 4 ресторан А закрыт, но на самом деле он открыт до 8:00. Если текущее время 7:00, ресторан A должен появиться открытым.
  2. Когда мы смотрим на № 1 и № 7, предыдущий день понедельника — это воскресенье. Таким образом, если текущее время понедельник, 7:00, запрос должен сравнить время с Открытое время воскресенья и дать результат "открыто".
  3. Также я хотел бы иметь запрос, который делает обратное, который находит рестораны, которые в настоящее время закрыты.

Это означает, что запрос должен иметь возможность решить, какие данные о времени использовать, сегодняшние или вчерашние. Пожалуйста, помогите мне найти решение.

Версия сервера MySQL — 10.4.17 MariaDB.

Тип данных No — int, все остальное — VARCHAR.

не могли бы вы опубликовать тип данных каждого поля и версию вашего сервера MySQL

Bernd Buffen 23.12.2020 08:56

Но проблема возникает, когда ресторан открывается вечером и заканчивается на следующий день. Преобразуйте значение времени в числовое и добавьте 240000 к Endtime, когда Starttime+0 > Endtime+0.

Akina 23.12.2020 09:17

Спасибо, Акина. Это было полезно. Но давайте предположим, что сейчас четверг, 7 утра. Согласно таблице, ресторан А все еще открыт, но добавление 24 часов к времени окончания четверга не поможет найти это.

user14796569 23.12.2020 10:09

@CharlieSchwab - можете опубликовать рисунок таблицы, чтобы увидеть типы данных. я видел, что также неправильное время в таблице. 24:00 неверно. Только 23:59:59 или 00:00:00. я знаю, что это не главная проблема

Bernd Buffen 23.12.2020 10:17

Я подозреваю, что вы используете MariaDB

Strawberry 23.12.2020 10:36
Освоение архитектуры микросервисов с Laravel: Лучшие практики, преимущества и советы для разработчиков
Освоение архитектуры микросервисов с Laravel: Лучшие практики, преимущества и советы для разработчиков
В последние годы архитектура микросервисов приобрела популярность как способ построения масштабируемых и гибких приложений. Laravel , популярный PHP...
Как построить CRUD-приложение в Laravel
Как построить CRUD-приложение в Laravel
Laravel - это популярный PHP-фреймворк, который позволяет быстро и легко создавать веб-приложения. Одной из наиболее распространенных задач в...
Освоение PHP и управление базами данных: Создание собственной СУБД - часть II
Освоение PHP и управление базами данных: Создание собственной СУБД - часть II
В предыдущем посте мы создали функциональность вставки и чтения для нашей динамической СУБД. В этом посте мы собираемся реализовать функции обновления...
Документирование API с помощью Swagger на Springboot
Документирование API с помощью Swagger на Springboot
В предыдущей статье мы уже узнали, как создать Rest API с помощью Springboot и MySql .
Роли и разрешения пользователей без пакета Laravel 9
Роли и разрешения пользователей без пакета Laravel 9
Этот пост изначально был опубликован на techsolutionstuff.com .
Как установить LAMP Stack - Security 5/5 на виртуальную машину Azure Linux VM
Как установить LAMP Stack - Security 5/5 на виртуальную машину Azure Linux VM
В предыдущей статье мы завершили установку базы данных, для тех, кто не знает.
1
5
102
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Вы можете разделить на 2 строки каждую строку, содержащую Endtime следующего дня:

WITH cte AS (
  SELECT *, Weekday day, Starttime time1, Endtime time2 FROM user_time
  WHERE Starttime < Endtime 
  UNION ALL
  SELECT *, Weekday, Starttime, '23:59' FROM user_time
  WHERE Starttime > Endtime 
  UNION ALL
  SELECT *, 
         DATE_FORMAT((STR_TO_DATE(CONCAT(LEFT(CURRENT_DATE, 8), Weekday), '%X-%V-%W') + INTERVAL 1 DAY), '%a'), 
         '00:00', Endtime 
  FROM user_time
  WHERE Starttime > Endtime
)  
SELECT No, Restaurant, Weekday, Starttime, Endtime 
FROM cte
WHERE day = DATE_FORMAT(CURRENT_DATE, '%a')
  AND NOW() BETWEEN CONCAT(CURRENT_DATE, ' ', time1, ':00') AND CONCAT(CURRENT_DATE, ' ', time2, ':00') 

Смотрите демо.

это не работает - ГДЕ день недели = DATE_FORMAT (CURRENT_DATE, '%a') будет генерировать день текущей даты, и если он позже 00:00 в столбце День недели был днем ​​​​вчера

Bernd Buffen 23.12.2020 11:35

@ forpas - я изменил ваш отчет, так что также должна быть выбрана строка № 9. Проблема в том, что день начала вчера, а время начала вчера больше, чем время начала сегодня. см. dbfiddle.uk/…

Bernd Buffen 23.12.2020 19:10

@BerndBuffen, вот почему в этом случае: время начала> время окончания, я разделяю строку на 2 строки, поэтому, если строка ('9', 'B', 'Вт', '22:00', '21:00' ) делится на ('9', 'Ч', 'Вт', '22:00', '23:59') и ('9', 'Ч', 'Ср', '00:00', «21:00»).

forpas 23.12.2020 19:17

о, о, о, моя ошибка!!! вы правы на 100%. ИЗВИНИТЕ.. Я уверен, что я уже в рождественской моде. - проголосовать за

Bernd Buffen 23.12.2020 19:22
Ответ принят как подходящий

Я построил таблицу с двумя новыми виртуальными полями. Эти поля заполняются автоматически. Я использую небольшую хитрость для буднего дня. Итак, я генерирую дату, а день недели - это день месяца. Он используется только для сравнения.

SELECT * 
FROM user_time
WHERE
    TIMESTAMP(CONCAT('2000-01-0',DAYOFWEEK(CURDATE()),' ',current_time()))
    BETWEEN date_start AND date_end
OR
    IF(DAYOFWEEK(CURDATE()) <> 'SUNDAY' , FALSE,
    TIMESTAMP(CONCAT('2000-01-0',DAYOFWEEK(CURDATE())+7,' ',current_time()))
    BETWEEN date_start AND date_end
    );

Таблица

CREATE TABLE `user_time` (
  `No` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `Restaurant` varchar(32) DEFAULT NULL,
  `Weekday` enum('SUNDAY','MONDAY','TUESDAY','WEDNESDAY','THURSDAY','FRIDAY','SATURDAY') DEFAULT NULL,
  `start_time` varchar(5) DEFAULT NULL,
  `end_time` varchar(5) DEFAULT NULL,
  `date_start` timestamp GENERATED ALWAYS AS (cast(concat('2000-01-0',`Weekday` + 0,' ',`start_time`) as datetime)) STORED,
  `date_end` timestamp GENERATED ALWAYS AS (cast(concat('2000-01-0',`Weekday` + 0,' ',`end_time`) + interval if (cast(`start_time` as time) >= cast(`end_time` as time),1,0) day as datetime)) STORED,
  PRIMARY KEY (`No`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8mb4;

вставьте некоторые данные

INSERT INTO `user_time` (`No`, `Restaurant`, `Weekday`, `start_time`, `end_time`)
VALUES
    (1, 'a', 'MONDAY', '12:00', '13:00'),
    (2, 'a', 'MONDAY', '14:00', '02:00'),
    (3, 'b', 'MONDAY', '16:00', '18:00'),
    (4, 'c', 'TUESDAY','21:00', '18:00');

посмотреть, что сгенерировано

MariaDB [bernd]> SELECT * FROM user_time;
+----+------------+---------+------------+----------+---------------------+---------------------+
| No | Restaurant | Weekday | start_time | end_time | date_start          | date_end            |
+----+------------+---------+------------+----------+---------------------+---------------------+
|  1 | a          | MONDAY  | 12:00      | 13:00    | 2000-01-02 12:00:00 | 2000-01-02 13:00:00 |
|  2 | a          | MONDAY  | 14:00      | 02:00    | 2000-01-02 14:00:00 | 2000-01-03 02:00:00 |
|  3 | b          | MONDAY  | 16:00      | 18:00    | 2000-01-02 16:00:00 | 2000-01-02 18:00:00 |
|  4 | c          | TUESDAY | 21:00      | 18:00    | 2000-01-03 21:00:00 | 2000-01-04 18:00:00 |
+----+------------+---------+------------+----------+---------------------+---------------------+
4 rows in set (0.01 sec)

MariaDB [bernd]> 

запросить текущую дату

MariaDB [bernd]> SELECT * 
    -> FROM user_time
    -> WHERE
    -> TIMESTAMP(CONCAT('2000-01-0',DAYOFWEEK(CURDATE()),' ',current_time()))
    -> BETWEEN date_start AND date_end;
+----+------------+---------+------------+----------+---------------------+---------------------+
| No | Restaurant | Weekday | start_time | end_time | date_start          | date_end            |
+----+------------+---------+------------+----------+---------------------+---------------------+
|  4 | c          | TUESDAY | 21:00      | 18:00    | 2000-01-03 21:00:00 | 2000-01-04 18:00:00 |
+----+------------+---------+------------+----------+---------------------+---------------------+
1 row in set (0.00 sec)

MariaDB [bernd]> 

Спасибо за глубокое исследование моей проблемы. Думаю, это решит первую проблему. Но как насчет второй проблемы? Что, если ресторан "а" открывается в 21:00 воскресенья и заканчивается в 11:00 понедельника? Если текущее время — 10:00 понедельника, ресторан «а» должен появиться открытым.

user14796569 23.12.2020 13:51

Это также работает. см. строку № 4. он открывается во ВТОРНИК в 21:00 и закрывается в СРЕДУ в 18:00. Сегодня СРЕДА, и он был выбран в моем запросе

Bernd Buffen 23.12.2020 14:18

Я имею в виду воскресенье 07.01.2000, верно? И понедельник 2000-01-01. Итак, как запрос может выбирать между воскресеньем и следующим понедельником?

user14796569 23.12.2020 14:39

я изменил первый запрос, но не тестировал

Bernd Buffen 23.12.2020 15:42

Другие вопросы по теме