如何在04:00>处理mysql中的“Open Till”时间23:00?

时间:2013-01-07 14:46:07

标签: mysql

我正在尝试查询关闭营业时间的查询。

问题在于,由于某些场馆在凌晨2,3,4点关闭 - 如果表格行值04:00对我来说比23:00更多,我怎么能查询where LESS THAN or EQUAL? / p>

谢谢!

4 个答案:

答案 0 :(得分:2)

我认为你应该使用datetime,timestamp或time作为数据类型。因为它将来可用于数学计算。

如果您将其存储为字符串或数字,则很难对其进行操作。

因此在选择数据类型时要具体。

答案 1 :(得分:2)

选择存储开始和结束时间的任意日期,例如1900年1月1日。

任何在同一天打开和关闭的商店都会使用此日期。

所以商店在上午9点开门,下午5点关门,获得:

开放时间:1900-01-01 09:00:00

关闭:1900-01-01 17:00:00

一天开业并关闭下一天的商店使用第二天作为收盘时间。

所以在下午4点开门并在第二天凌晨2点关门的酒吧得到:

开放时间:1900-01-01 16:00:00

关闭:1900-01- 02 02:00:00

现在您可以使用大于或小于查询并获得您期望的结果。

答案 2 :(得分:2)

由于关闭时间必须在开放时间之后发生,如果closing_time小于opening_time,则意味着间隔在第二天滚动。

如何检查给定时间是否在某个时间间隔内?如果出现以下情况,则给定时间在一个区间内:

  • given_time介于opening_timeclosing_time之间,当间隔未翻转时;
  • given_time不在opening_timeclosing_time之间,关闭时间是在第二天。

据我记得,我以前从未在SQL查询中使用 XOR ,但这里完全适合:

closing_time<opening_time
XOR
  (time(now()) >= least(opening_time,closing_time) and
   time(now()) < greatest(opening_time, closing_time))
如果time(now())在任何时间间隔内,即使closing_time小于opening_time,

也会返回true。请注意,我必须使用>=<,使用>=<=(或其等效的BETWEEN)并不总能给出正确的结果,但我相信逻辑是对的。

如果我们必须检查时间(now())是否在特定数据的区间内,我们仍有问题:如果商店在星期一打开,并在凌晨1点关闭,则关闭时间不再在星期一,因此,如果我们过去中间,并且间隔被交换,我们必须检查前一天的间隔。这会检查正确的opening_day:

opening_day =
date_format(now() - INTERVAL
    (closing_time<opening_time and time(now())<closing_time) DAY, '%a'))

如果closing_time在第二天滚动,并且当前时间在关闭时间之前,则()中的条件将为真,因此我们必须检查INTERVAL 1 DAY,否则condition为false并且减去INTERVAL 0 DAY给出当前日期。

所以我的最后一个问题是:

set @n='2013-01-11 18:15:00';

SELECT
  e.name,
  hrs.opening_day,
  hrs.opening_time,
  hrs.closing_time
FROM
  hours_of_operation hrs join establishments e
  on hrs.establishment_id = e.id
     and not is_closed
     and ((hrs.opening_day=date_format(@n -
           INTERVAL
             (closing_time<opening_time and time(@n)<closing_time)
           DAY, '%a'))
          AND (closing_time<opening_time XOR
         (time(@n) >= least(opening_time,closing_time)
          and time(@n) < greatest(opening_time, closing_time))))
 ;

使所有商店在给定的@n日期时间打开。 Fiddle is here

修改

我有另一个(也许是奇怪的?)想法来解决同样的问题。它应该更容易理解。 2001年的第一天是'2001-01-01',这是一个看起来不错的日期,也有一个星期一的有趣特性。所以我的想法是将所有日期(当前日期,开放日期,结束日期)转回到此日期。

当前日期将变为:

'2001-01-01'
+ INTERVAL WEEKDAY( @n ) DAY
+ INTERVAL TIME_TO_SEC( @n ) SECOND

(我们添加星期几,星期一的工作日为0所以我们仍然会在'2001-01-01',星期二是1所以它将是'2001-01-02'等等) 。并使用TIME_TO_SEC我添加第二个来创建日期时间字段。

开幕日期为:

'2001-01-01'
+ INTERVAL
    FIELD(opening_day,'Mon','Tue','Wed','Thu','Fri','Sat','Sun')-1
  DAY
+ INTERVAL TIME_TO_SEC(opening_time) SECOND

要将opening_day转换为我正在使用FIELD函数添加的天数,那么我们必须从星期一开始减1,然后我们添加时间部分。

截止日期为:

'2001-01-01'
 + INTERVAL
     FIELD(opening_day,'Mon','Tue','Wed','Thu','Fri','Sat','Sun')
     -(closing_time>opening_time) DAY
 + INTERVAL TIME_TO_SEC(closing_time) SECOND

与开放日期相同,但是我只减去1到DAY只有opening_time在closing_time之前,否则意味着closing_time在第二天发生。然后我们只需要使用BETWEEN来检查我们是否在这个区间内,如下所示:

SELECT
  establishments.id,
  establishments.name,
  opening_time,
  closing_time
FROM
  `hours_of_operation` inner join establishments
  on hours_of_operation.establishment_id=establishments.id
     and not is_closed
     and
       '2001-01-01'
       + INTERVAL WEEKDAY( @n ) DAY
       + INTERVAL TIME_TO_SEC( @n ) SECOND

       BETWEEN

       '2001-01-01'
       + INTERVAL
           FIELD(opening_day,'Mon','Tue','Wed','Thu','Fri','Sat','Sun')-1
         DAY
       + INTERVAL TIME_TO_SEC(opening_time) SECOND

       AND

      '2001-01-01'
      + INTERVAL
          FIELD(opening_day,'Mon','Tue','Wed','Thu','Fri','Sat','Sun')
          -(closing_time>opening_time) DAY
      + INTERVAL TIME_TO_SEC(closing_time) SECOND

Fiddle here

但是在这一点上,我们可以从周初开始转换为秒,我们有所有元素都可以执行此操作,我的最终查询将是:

SELECT
  establishments.id,
  establishments.name,
  opening_time,
  closing_time
FROM
  `hours_of_operation` inner join establishments
  on hours_of_operation.establishment_id=establishments.id
     and not is_closed
     and
       WEEKDAY( @n ) * 86400 + TIME_TO_SEC( @n )    

       BETWEEN

       (FIELD(opening_day,'Mon','Tue','Wed','Thu','Fri','Sat','Sun')-1)*86400+
        TIME_TO_SEC(opening_time)

       AND

       (FIELD(opening_day,'Mon','Tue','Wed','Thu','Fri','Sat','Sun')
        -(closing_time>opening_time))*86400
        + TIME_TO_SEC(closing_time)

答案 3 :(得分:1)

您必须检查closing_time是否小于opening_time才能知道这是第二天。

要获得给定日期时间的有效开放时间,您还必须检查给定日期时间是否小于开放时间以创建正确的时间间隔。

要获取给定日期时间的开放时间

SET @MyDate = Now();

SELECT 
  title,
  CAST( 
    CONCAT( 
      CASE 
        WHEN TIME( @MyDate ) < opening THEN 
          DATE( @MyDate ) - INTERVAL 1 DAY 
        ELSE DATE( @MyDate ) 
      END, ' ', opening 
    ) AS DATETIME 
  ) open_from, 
  CASE 
    WHEN opening > closing THEN 
      CAST( 
        CONCAT( 
          CASE 
            WHEN TIME( @MyDate ) < opening THEN 
              DATE( @MyDate ) - INTERVAL 1 DAY 
            ELSE DATE( @MyDate ) 
          END + INTERVAL 1 DAY, ' ', closing 
        ) AS DATETIME 
      )
    ELSE 
      CAST( 
        CONCAT( 
          CASE 
            WHEN TIME( @MyDate ) < opening THEN 
              DATE( @MyDate ) - INTERVAL 1 DAY 
            ELSE DATE( @MyDate ) 
          END, ' ', closing 
        ) AS DATETIME 
      )
  END open_till
FROM 
  stores
ORDER BY
  open_from;

要获得实际的open / closed州使用

SET @MyDate = Now();

SELECT 
  title, 
  CASE
    WHEN 
      @MyDate >= CAST( CONCAT( CASE 
                           WHEN TIME( @MyDate ) < opening THEN 
                             DATE( @MyDate ) - INTERVAL 1 DAY 
                           ELSE DATE( @MyDate ) 
                         END, ' ', opening ) AS DATETIME )
    AND 
      @MyDate < CASE 
                WHEN opening > closing 
                THEN CAST( CONCAT( CASE 
                               WHEN TIME( @MyDate ) < opening THEN 
                                 DATE( @MyDate ) - INTERVAL 1 DAY 
                               ELSE DATE( @MyDate ) 
                             END + INTERVAL 1 DAY, ' ', closing ) AS DATETIME )
                ELSE CAST( CONCAT( CASE 
                               WHEN TIME( @MyDate ) < opening THEN 
                                 DATE( @MyDate ) - INTERVAL 1 DAY 
                               ELSE DATE( @MyDate ) 
                             END, ' ', closing ) AS DATETIME )
              END
    THEN 'open'
    ELSE 'closed'
  END state
FROM 
  stores;

SQL Fiddle DEMO

<强>更新

我已经处理了您的SQL Fiddle Sample并删除了过时的专栏closing_day

SET @MyTime = Now();

SELECT
  ho.`establishment_id`, e.`name`
FROM
  `hours_of_operation` ho
JOIN
  `establishments` e ON ho.`establishment_id` = e.`id`
WHERE
  NOT `is_closed`
AND
  `opening_day` = DATE_FORMAT( CASE 
                                 WHEN TIME( @MyTime ) < `opening_time` THEN 
                                   DATE( @MyTime ) - INTERVAL 1 DAY 
                                 ELSE 
                                   DATE( @MyTime ) 
                               END, '%a' )
AND
  @MyTime >= CAST( CONCAT( CASE 
                             WHEN TIME(@MyTime) < ho.`opening_time` THEN 
                               DATE( @MyTime ) - INTERVAL 1 DAY 
                             ELSE 
                               DATE( @MyTime ) 
                           END, ' ', ho.`opening_time` ) AS DATETIME )
AND
  @MyTime < CAST( CASE
                    WHEN ho.`opening_time` > ho.`closing_time` THEN
                      CONCAT( CASE 
                                WHEN TIME(@MyTime) < ho.`opening_time` THEN 
                                  DATE( @MyTime ) - INTERVAL 1 DAY 
                                ELSE 
                                  DATE( @MyTime ) 
                              END + INTERVAL 1 DAY, ' ', ho.`closing_time` )
                    ELSE
                      CONCAT( CASE 
                                WHEN TIME(@MyTime) < ho.`opening_time` THEN
                                  DATE( @MyTime ) - INTERVAL 1 DAY 
                                ELSE 
                                  DATE( @MyTime ) 
                              END, ' ', ho.`closing_time` )
                  END AS DATETIME );

解决方案基于上面公布的相同方法,但会检查每个工作日的营业时间。

SQL Fiddle DEMO