3

私は Postgres 8.3 を使用しています (現時点ではバージョンの選択肢はありません)。私の生データテーブルは次のとおりです。

ID  start_time               finish_time
01   2013-01-23 10:47:52-05  2013-02-25 11:18:36-05

2 つのタイムスタンプを数えることができます。

--relevant line in view creation query:
date_part('epoch',(finish_time - start_time)::interval)/3600 as hours

週末は含めたくありません。また、09:00 - 17:30 のみをカウントしたいです。

完璧な世界では、1 日あたりの昼食時間も 1 時間引き、最終的には会社の休日も含めたいと考えていますが、最初にこの労働時間の部分を解決したいと考えています。

これにアプローチする方法について何かアドバイスはありますか?私はSQLにかなり慣れていません。私は SQLalchemy を使用することにもオープンですが、初心者でもあり、ストレート SQL の方が快適だと感じています。

4

2 に答える 2

3

これにより、@Catcall によって提供される進行中の作業が進められます

SELECT count(*)
FROM   generate_series(0, extract(days from timestamp '2013-02-25 11:18:36' 
                                          - timestamp '2013-01-23 10:47:52')::int * 24) n
WHERE  extract(ISODOW from timestamp '2013-01-23 10:47:52' + n * interval '1h') < 6
AND   (timestamp '2013-01-23 10:47:52' + n * interval '1h')::time >= '09:00'::time
AND   (timestamp '2013-01-23 10:47:52' + n * interval '1h')::time <  '17:30'::time
  • timestamp '2013-01-23 10:47:52-05'あなたが考えているように見えることをしていません。-05リテラルを にキャストしたため、タイム ゾーン オフセットは破棄されますtimestamp [without timezone]。あなたはおそらく望んでいtimestamptz '2013-01-23 10:47:52-05'た。ただし、通常、勤務時間は現地時間に拘束されるため、最初はその方が適切であると主張できますtimestamp [without time zone]。この関連する回答の詳細:
    Rails と PostgreSQL でタイムゾーンを完全に無視する

  • このフォームははるかに効率的です

    timestamptz '2013-01-23 10:47:52-05' + n * interval '1h'
    

    これより:

    timestamptz '2013-01-23 10:47:52-05' + (n || ' hours')::interval
    

    任意の間隔を単純に掛けることができます。

関数

さらに開発し、SQL 関数にラップしました。
まだ正確ではありませんが、系統誤差が修正され、30 分単位による丸め誤差が小さくなっています。

CREATE OR REPLACE FUNCTION f_worktime83(t_start timestamp
                                      , t_end timestamp)
  RETURNS interval AS
$func$

SELECT (count(*) - 1) * interval '30 min' -- fix off-by-one error
FROM   (
   SELECT $1 + generate_series(0, (extract(epoch FROM $2 - $1)/1800)::int)
             * interval '30 min' AS t
   ) sub
WHERE  extract(ISODOW from t) < 6
AND    t::time >= '09:00'::time
AND    t::time <  '17:30'::time

$func$  LANGUAGE sql

電話:

SELECT f_worktime83('2013-06-26 10:47:52', '2013-06-26 11:10:51')
  • 値を直接追加しgenerate_series()て、コードを簡素化します。
  • (秒数) を抽出し、それを(30 分epocの秒数) で割ることにより、(四捨五入された) 正確な時間単位数を取得します。1800
  • カウントに上限境界を含めて発生する off-by-1 エラーを修正しました。
于 2013-06-26T02:42:54.373 に答える