店舗の閉店時間をクエリ検索しようとしています。
where LESS THAN or EQUAL
問題は、一部の会場は午前 2、3、4 時に閉店するため、表の行の値が 04:00 であることが 23:00 よりも重要な意味を持つ場合、クエリを実行するにはどうすればよいかということです。
ありがとう!
店舗の閉店時間をクエリ検索しようとしています。
where LESS THAN or EQUAL
問題は、一部の会場は午前 2、3、4 時に閉店するため、表の行の値が 04:00 であることが 23:00 よりも重要な意味を持つ場合、クエリを実行するにはどうすればよいかということです。
ありがとう!
閉店時間は開場時間の後に発生する必要があるため、それ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())
、closeing_timeがopening_timeよりも小さい場合でも、が任意の間隔内にある場合にtrueになります。>=
and<
を使用>=
しなければならなかったことに注意してください<=
。and(または同等のBETWEEN)を使用しても、常に正しい結果が得られるとは限りませんが、ロジックは正しいと思います。
time(now())が特定の日付の間隔内にあるかどうかを確認する必要がある場合でも、問題が発生します。店舗が月曜日に開店し、午前1時に閉店すると、閉店時間は月曜日ではなくなります。月曜日を過ぎており、間隔が入れ替わっている場合は、前日の間隔を確認する必要があります。これにより、正しいopening_dayがチェックされます。
opening_day =
date_format(now() - INTERVAL
(closing_time<opening_time and time(now())<closing_time) DAY, '%a'))
翌日にcloseing_timeがロールされ、現在の時刻が終了時刻より前の場合、()の条件はtrueになるため、INTERVAL 1 DAYをチェックする必要があります。そうでない場合、条件はfalseであり、INTERVAL0DAYを引くと現在の日付になります。
だから私の最後のクエリはこれです:
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日時にオープンします。フィドルはここにあります。
編集:
同じ問題を解決するための別の(おそらく奇妙な?)アイデアがありました。少しわかりやすいはずです。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を使用して、日時フィールドを作成するために2番目を追加しています。
開業日は次のようになります。
'2001-01-01'
+ INTERVAL
FIELD(opening_day,'Mon','Tue','Wed','Thu','Fri','Sat','Sun')-1
DAY
+ INTERVAL TIME_TO_SEC(opening_time) SECOND
open_dayを追加する日数に変換するには、FIELD関数を使用しています。ここでは、月曜日が1から始まるため、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
開始日と同じですが、DAYに1を引くと、opening_timeはcloseing_timeの前になります。それ以外の場合は、closeing_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)
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
大なりおよび小なりクエリを使用して、期待どおりの結果を得ることができるようになりました。
datetime、timestamp、または time をデータ型として使用する必要があると思います。将来、数学の計算に役立つからです。
文字列または数値として保存すると、何かを行うのが難しくなります。
したがって、データ型を選択するときは具体的にしてください。
これが翌日になることを意図していることを知るには、 がそれ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 );
ソリューションは、上記と同じアプローチに基づいていますが、平日の営業時間をチェックします。