0

私は次のようなテーブルを持っています:

CREATE TABLE `zonetimes` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `zone_id` int(10) unsigned NOT NULL,
  `active_from_day` tinyint(1) unsigned NOT NULL DEFAULT '2',
  `active_to_day` tinyint(1) unsigned NOT NULL DEFAULT '2',
  `active_from` time NOT NULL,
  `active_to` time NOT NULL
  PRIMARY KEY (`id`)
) ENGINE=MyISAM ;

したがって、ユーザーは、特定の日時に開始し、特定の日時に終了する時間エントリを追加できます。たとえば、月曜日の08:00から金曜日の18:00の間、または木曜日の15:00から火曜日の15:00の間です(注週末のクロスオーバー)。

このデータをクエリして、ゾーンが現在アクティブであるかどうかを判断する必要があります(NOW()、DAYOFWEEK()など)...これは非常に注意が必要です。

重複がなかった場合、たとえば、「水曜日の午後8時から火曜日の午前4時」または「木曜日の午後4時から火曜日の午後4時」の場合、これはBETWEENで簡単になります。

また、ユーザーが1週間全体を追加できるようにする必要があります。例:月曜日の午前8時から月曜日の午前8時(これは簡単なはずです。例:where(active_from_day = active_to_day AND active_from = active_to)OR ..

何か案は?

注:ここで同様の質問を見つけました。タイムスパン-mysqlで平日と時刻を確認しましたが、回答が得られませんでした。提案の1つは、毎日別々の行として保存することでした。ただし、1つの期間を複数日保存したいと思います。

アップデート

以下のTerjeDのクエリは完全に機能します。いくつかのテストシナリオ:

+---------------------+-----------------+---------------+-------------+-----------+------------+
| NOW( )              | active_from_day | active_to_day | active_from | active_to | active_now |
+---------------------+-----------------+---------------+-------------+-----------+------------+
| 2012-10-31 23:41:55 |               1 |             4 | 08:00:00    | 23:40:00  |          0 |
| 2012-10-31 23:42:25 |               1 |             4 | 08:00:00    | 23:45:00  |          1 |
| 2012-10-31 23:42:57 |               4 |             1 | 08:00:00    | 09:45:00  |          1 |
| 2012-10-31 23:43:36 |               4 |             4 | 23:00:00    | 09:45:00  |          1 |
| 2012-10-31 23:44:10 |               5 |             4 | 00:00:00    | 23:44:00  |          0 |
| 2012-10-31 23:44:27 |               5 |             4 | 00:00:00    | 23:45:00  |          1 |
| 2012-10-31 23:45:14 |               2 |             2 | 00:00:00    | 00:00:00  |          0 |

上記の結果は、Terjeのクエリを数回実行することによって生成されました。

SELECT NOW( ) , active_from_day, active_to_day, active_from, active_to, (
DAYOFWEEK( NOW( ) ) > active_from_day
OR DAYOFWEEK( NOW( ) ) = active_from_day
AND TIME( NOW( ) ) > active_from
)
AND (
DAYOFWEEK( NOW( ) ) < active_to_day
OR DAYOFWEEK( NOW( ) ) = active_to_day
AND TIME( NOW( ) ) < active_to
)
OR (
active_from_day > active_to_day
OR active_from_day = active_to_day
AND active_from > active_to
)
AND (
(
DAYOFWEEK( NOW( ) ) > active_from_day
OR DAYOFWEEK( NOW( ) ) = active_from_day
AND TIME( NOW( ) ) > active_from
)
OR (
DAYOFWEEK( NOW( ) ) < active_to_day
OR DAYOFWEEK( NOW( ) ) = active_to_day
AND TIME( NOW( ) ) < active_to
)
) AS active_now FROM zonetimes
4

2 に答える 2

1

このロジックは次のように機能する必要があります。

IF active_to >= active_from AND NOW() BETWEEN active_from AND active_to
OR active_to < active_from AND NOW NOT BETWEEN active_to AND active_from

すなわち

IF (DAYOFWEEK(NOW()) > active_from_day 
   OR DAYOFWEEK(NOW()) = active_from_day AND TIME(NOW()) > active_from)
AND (DAYOFWEEK(NOW()) < active_to_day
   OR DAYOFWEEK(NOW()) = active_to_day AND TIME(NOW()) < active_to)
OR (active_from_day > active_to_day 
   OR active_from_day = active_to_day AND active_from > active_to)
AND ((DAYOFWEEK(NOW()) > active_from_day 
   OR DAYOFWEEK(NOW()) = active_from_day AND TIME(NOW()) > active_from)
OR (DAYOFWEEK(NOW()) < active_to_day
   OR DAYOFWEEK(NOW()) = active_to_day AND TIME(NOW()) < active_to))

(時間が開始後と終了前の両方である場合、または開始>終了であり、時間が開始後または終了前の場合、ゾーンはアクティブです)

于 2012-10-31T07:40:19.753 に答える
0

これをスクラップして、TerjeDの答えを見てください。

Skpdのアイデアを使用した1つの可能な方法(結果として乱雑なクエリが発生します):

開始日(月曜日から日曜日はtinyint 0から6)を作成し、次に開始時間(深夜からint分)と範囲(int分)を作成しました。したがって、ゾーンがアクティブである期間は、(day_of_week + start)と(day_of_week + start + range)の間にあります。queryigの場合、先週の期間と今週の期間の両方を取得します。もっとエレガントなアプローチがあると確信していますが、それはすべての組み合わせで機能すると思います。ストレージを最小限に抑えます

CREATE TABLE `azonetimes` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `zone_id` int(10) unsigned NOT NULL,
  `day_of_week` tinyint(1) unsigned NOT NULL DEFAULT '2',
  `start` int(11) unsigned NOT NULL DEFAULT '0',
  `range` int(11) unsigned NOT NULL DEFAULT '0',
  PRIMARY KEY (`id`)
) ENGINE=MyISAM ;

クエリ:(水曜日の午前7時50分)

    SELECT 
        azonetimes.*, (
            NOW() 
            #Check for last week
            BETWEEN     
                        (FROM_UNIXTIME(UNIX_TIMESTAMP(DATE(CURDATE() - INTERVAL WEEKDAY( CURDATE() ) - CAST(azonetimes.day_of_week AS SIGNED INT) +
                        IF( WEEKDAY( CURDATE() ) >  CAST(azonetimes.day_of_week AS SIGNED INT), 0, 7 ) - 7 DAY )) + `start`*60) )
                    AND (FROM_UNIXTIME(UNIX_TIMESTAMP(DATE(CURDATE() - INTERVAL WEEKDAY( CURDATE() ) - CAST(azonetimes.day_of_week AS SIGNED INT) +
                        IF( WEEKDAY( CURDATE() ) >  CAST(azonetimes.day_of_week AS SIGNED INT), 0, 7 ) - 7 DAY )) + ((`range` + `start`)*60)))
            )
        OR 
        (
            NOW() 
            #Check for this week
            BETWEEN     
                        (FROM_UNIXTIME(UNIX_TIMESTAMP(DATE(CURDATE() - INTERVAL WEEKDAY( CURDATE() ) - CAST(azonetimes.day_of_week AS SIGNED INT) +
                        IF( WEEKDAY( CURDATE() ) >  CAST(azonetimes.day_of_week AS SIGNED INT), 0, 7 )  DAY )) + `start`*60) )
                    AND (FROM_UNIXTIME(UNIX_TIMESTAMP(DATE(CURDATE() - INTERVAL WEEKDAY( CURDATE() ) - CAST(azonetimes.day_of_week AS SIGNED INT) +
                        IF( WEEKDAY( CURDATE() ) >  CAST(azonetimes.day_of_week AS SIGNED INT), 0, 7 )  DAY )) + ((`range` + `start`)*60)))
            )
        AS open
        FROM azonetimes


+----+---------+-------------+-------+-------+------+
| id | zone_id | day_of_week | start | range | open |
+----+---------+-------------+-------+-------+------+
|  1 |       1 |           2 |   300 |   900 |    1 |   << Wed 5am to 8pm
|  2 |       0 |           1 |     0 |  2400 |    1 |   << Tue 00:00 to Wed 4pm (40 hrs)
|  3 |       4 |           4 |   300 |   900 |    0 |   << Fri 5am to 8pm
|  4 |       0 |           5 |   900 |  7200 |    1 |   << Sat 3pm to Thu 3pm
+----+---------+-------------+-------+-------+------+
于 2012-10-31T07:59:39.270 に答える