web-dev-qa-db-ja.com

2時間の列の1時間を比較する

助けてください。私はこのデータベースの世界に少し新しいです。 PostgreSQLを使用しています。

次のようにシフトが定義されたテーブルがあります。

CREATE TEMPORARY TABLE shifts AS
SELECT id, start_hour::time, end_hour::time
FROM ( VALUES 
  ( 1,'06:00:01','14:00:00' ),
  ( 2,'14:00:01','22:00:00' ),
  ( 3,'22:00:01','06:00:00' )
) AS t(id,start_hour,end_hour);

私はbetween演算子を使用して、指定された時間をstart_hourおよびend_hourと比較して、次のように対応するシフトを取得しています

SELECT * from Shifts S where given_hour BETWEEN start_hour AND end_hour;

シフト1または2のときに機能しますが、シフト3では機能しません。値を返しません。これをどのように行うべきかについて少しアドバイスをいただけますか?ありがとうございました!

1
Andy

「終了」で定義された間隔を「開始」よりも小さくすることはできません。日の境界を越えているため、シフト3は機能せず、「終了」(6時、終了の22時よりも小さい)。

時間単位でシフトを定義する場合は、通常、シフトごとに2つの間隔が必要で、シフト3には次のものが必要です。

+----+--------------+------------+--------------+------------+
| id | start_hour_1 | end_hour_1 | start_hour_2 | end_hour_2 |
+----+--------------+------------+--------------+------------+
|  1 |     06:00:00 |   14:00:00 |              |            |
+----+--------------+------------+--------------+------------+
|  2 |     14:00:00 |   22:00:00 |              |            |
+----+--------------+------------+--------------+------------+
|  3 |     22:00:00 |   24:00:00 |    00:00:00  |   06:00:00 |
+----+--------------+------------+--------------+------------+

また、クエリを次のように書き換える必要があります。

SELECT 
    * 
FROM 
    Shifts S 
WHERE
       (given_hour >= start_hour_1 AND given_hour < end_hour_1)
    OR (given_hour >= start_hour_2 AND given_hour < end_hour_2) ;

少しアドバイスとして、BETWEEN .. AND ..discrete変数(基本的には整数とテキスト)のみ。 continuous変数(および時間iscontinuous)を使用すると、include終わりの1つとexcludeもう一方の(>= AND <)given_hour >= start_time AND given_hour < end_time。それが私が:01を:00でこのように動作するように変更した理由です(そして14:00:00.123の問題を回避します(これはが起こり得るが最終的に発生します))。

1
joanolo

いくつかのオプションがあります。本質的に、これはそれを解決することになると鶏と卵の問題です。

ある日ビジネスを始めて、このスキーマを使い始めたとしましょう。_3:00:00_が機能したかどうかは、どのシフトが始まったかによって異なります。

  1. dayという朝のシフトでその日を開始した場合、誰も午前3時に働いていません。
  2. 墓地のシフトで3時間働くdayを呼び出すことによって真夜中に1日を開始した場合、午前3時が働いていました。

そのデータは永久に失われ、あいまいさは最初のシフトに戻って日付を追加しない限り解決できません。

その時点で、timetimestamp(日付要素を含む)になります。次に、元のクエリのように、日付が添付されているため、誰が何時に働いたかを知るのが簡単です。したがって、原則として、実際の日付から切り離されていないか、または抽象的な繰り返しイベントを表している場合を除いて、timeを使用しないでくださいです。あなたはそのルールに違反しました、そして今あなたはたくさんの楽しみを持っているでしょう。

だから私たちができることは、この問題を解決するために疑似日付要素を作成することです。最初のシナリオを想定して解決します。

_SELECT 'yesterday'::date + start_hour AS start, 'yesterday'::date + start_hour + work_time AS end
FROM (
  SELECT start_hour,
    end_hour,
    CASE WHEN (end_hour<start_hour)
      THEN ('24:0:0' - start_hour) + (end_hour - 'ALLBALLS'::time)
      ELSE end_hour - start_hour
    END AS work_time
  FROM shifts
) AS t;
_

これで、午前3時にクエリを実行できます。

_-- change this to get the query result you want.
WHERE ('TODAY'::date + '3:00:00'::time)
  BETWEEN ('YESTERDAY'::date + start_hour)
    AND ('YESTERDAY'::date + start_hour + work_time);
_

または、8 PMでクエリを実行できます。

_-- change this to get the query result you want.
WHERE ('YESTERDAY'::date + '8:00:00'::time)
  BETWEEN ('YESTERDAY'::date + start_hour)
    AND ('YESTERDAY'::date + start_hour + work_time);
_

しかし、最終的にはおそらく、タイムスタンプを使用するようにスキーマを修正したいでしょう。

0
Evan Carroll