我正在尝试查询关闭营业时间的查询。
问题在于,由于某些场馆在凌晨2,3,4点关闭 - 如果表格行值04:00对我来说比23:00更多,我怎么能查询where LESS THAN or EQUAL
? / p>
谢谢!
答案 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_time
和closing_time
之间,当间隔未翻转时; given_time
不在opening_time
和closing_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
但是在这一点上,我们可以从周初开始转换为秒,我们有所有元素都可以执行此操作,我的最终查询将是:
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 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 );
解决方案基于上面公布的相同方法,但会检查每个工作日的营业时间。