2

店舗の閉店時間をクエリ検索しようとしています。

where LESS THAN or EQUAL問題は、一部の会場は午前 2、3、4 時に閉店するため、表の行の値が 04:00 であることが 23:00 よりも重要な意味を持つ場合、クエリを実行するにはどうすればよいかということです。

ありがとう!

4

4 に答える 4

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())、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)
于 2013-01-10T23:37:33.330 に答える
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

大なりおよび小なりクエリを使用して、期待どおりの結果を得ることができるようになりました。

于 2013-01-10T14:48:54.417 に答える
2

datetime、timestamp、または time をデータ型として使用する必要があると思います。将来、数学の計算に役立つからです。

文字列または数値として保存すると、何かを行うのが難しくなります。

したがって、データ型を選択するときは具体的にしてください。

于 2013-01-07T14:57:10.770 に答える
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;

使用実態openclosed状態を知るには

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 フィドルのデモ

アップデート

私はあなたの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 フィドルのデモ

于 2013-01-10T09:48:40.337 に答える