3

チケットを受信して​​からの応答時間を決定するストアド プロシージャを更新しようとしています。テーブルには、チケットが受信されたときのタイムスタンプ (ref_dttm TIMESTAMP WITHOUT TIME ZONE) と、チケットが最初に応答されたときのタイムスタンプ (first_action_dttm TIMESTAMP WITHOUT TIME ZONE) があります。応答時間を計算するときは、営業時間、週末、および祝日の休業日を考慮する必要があります。

現在、この関数は間隔を計算し、休業時間を差し引くことができますが、週末と休日を除外する方法がわかりません。基本的に、平日 (09:00 ~ 18:00 まで営業) で 15 時間、週末と祝日で 24 時間を差し引く必要があります。

チケットを受け取る曜日と期間を考えると、次のようになります。

Select 
    extract(dow from ref_dttm) as dow, 
    extract(days from (ref_dttm - first_action_dttm) as days

週末が何回過ぎたかを簡単に判断する方法はありますか?

これは私がこれまでに持っているものです-1日あたり15時間を差し引いており、週末は考慮されていません:

CREATE TEMP TABLE tmp_ticket_delta ON COMMIT DROP AS
  SELECT id,ticket_id,ticket_num
    ,(ticket_dttm - first_action_dttm) as delta
    ,extract(days from (ticket_dttm - first_action_dttm)) as days
    ,ticket_descr
  FROM t_tickets
  WHERE ticket_action_by > 0

SELECT id,ticket_id,ticket_num,delta,days,ticket_descr,
  CASE WHEN days = 0 THEN
    CASE WHEN extract(hour from delta) > 15 THEN
      --less than one day but outside of business hours so subtract 15 hrs
      delta - INTERVAL '15:00:00.000'
    ELSE
      delta
    END
  ELSE
    CASE WHEN extract(hour from delta) > 15 THEN
      --take the total number of hours - closing hours + delta - closed hours
      (((days * 24) - (days * 15)) * '1 hour'::INTERVAL) + delta - INTERVAL '15:00:00.000' - (days * '1 day'::INTERVAL)
    ELSE
      (((days * 24) - (days * 15)) * '1 hour'::INTERVAL) + delta - (days * '1 day'::INTERVAL)
    END 
  END AS adj_diff
FROM tmp_ticket_delta
4

3 に答える 3

1

重要なビジネス データをテーブルに格納するのが好きです。このようなクエリ

select min(cal_date), 
       max(cal_date), 
       sum(hours_open) total_time_open, 
       sum(hours_closed) total_time_closed
from daily_hours_open_and_closed
where cal_date between '2013-08-28' and '2013-09-03';

単純なテーブルに格納されたデータに基づいている場合、理解しやすく、維持しやすく、デバッグしやすいです。

カレンダー テーブルから始めて、あなたの場所が開いている時間のテーブルを追加します。このテーブル「open_times」は、開始する最も簡単な方法ですが、ビジネスには単純すぎる場合があります。たとえば、より厳密な CHECK 制約が必要になる場合があります。また、これを効率的にしようとはしていませんが、最終的なクエリは開発ボックスでわずか 12 ミリ秒で実行されます。

create table open_times (
  bus_open timestamp primary key,
  bus_closed timestamp not null
    check (bus_closed > bus_open)
);

そのテーブルに 2013 年の平日の時間を入力する手っ取り早い方法です。

with openings as (
  select generate_series(timestamp '2013-01-01 09:00', 
                         timestamp '2013-12-31 18:00', '1 day') bus_open
)
insert into open_times
select bus_open, bus_open + interval '9 hours' bus_closed
from openings
where extract(dow from bus_open) between 1 and 5
order by bus_open;

労働者の日はここで休日なので、9 月 2 日月曜日は休日です。2013-09-02 を削除します。

delete from open_times
where bus_open = '2013-09-02 09:00';

これは、これがどのように機能するかを示す目的で私が興味を持っている唯一の休日です。もちろん、あなたは私よりもうまくやる必要があります。

さらに簡単にするために、毎日の稼働時間をインターバルとして表示するビューを作成します。

create view daily_hours_open_and_closed as
select c.cal_date, 
       ot.bus_open,
       ot.bus_closed,
       coalesce(bus_closed - bus_open, interval '0 hours') as hours_open,
       interval '24 hours' - (coalesce(bus_closed - bus_open, interval '0 hours')) as hours_closed
from calendar c
left join open_times as ot 
       on c.cal_date = cast(ot.bus_open as date);

さて、2013 年 8 月 28 日から 2013 年 9 月 3 日までの 7 日間、営業時間と休業時間はそれぞれ何時間ですか。生データのクエリは非常にシンプルになりました。

select *
from daily_hours_open_and_closed
where cal_date between '2013-08-28' and '2013-09-03'
order by cal_date;

cal_date     bus_open              bus_closed            hours_open  hours_closed
--
2013-08-28   2013-08-28 09:00:00   2013-08-28 18:00:00   09:00:00    15:00:00
2013-08-29   2013-08-29 09:00:00   2013-08-29 18:00:00   09:00:00    15:00:00
2013-08-30   2013-08-30 09:00:00   2013-08-30 18:00:00   09:00:00    15:00:00
2013-08-31                                               00:00:00    24:00:00
2013-09-01                                               00:00:00    24:00:00
2013-09-02                                               00:00:00    24:00:00
2013-09-03   2013-09-03 09:00:00   2013-09-03 18:00:00   09:00:00    15:00:00

集計関数を使用して算術を実行します。

select min(cal_date), 
       max(cal_date), 
       sum(hours_open) total_time_open, 
       sum(hours_closed) total_time_closed
from daily_hours_open_and_closed
where cal_date between '2013-08-28' and '2013-09-03'

min          max          total_time_open   total_time_closed
--
2013-08-28   2013-09-03   36:00:00           132:00:00
于 2013-08-27T13:09:17.873 に答える
0

次のクエリのようなもので週末をカウントできます。

select
    *,
    (extract(week from ref_dttm) - extract(week from first_action_dttm)) * 2 -
    case extract(dow from first_action_dttm) when 0 then 1 else 0 end +
    case extract(dow from ref_dttm) when 0 then 2 when 6 then 1 else 0 end
from t_tickets

試着するsql fiddle demo

または、日付が異なる年になる可能性がある場合:

select
    *,
    trunc(date_part('day', ref_dttm - first_action_dttm) / 7) * 2 + 
    case extract(dow from first_action_dttm) when 0 then 1 when 6 then 2 else 0 end + 
    case extract(dow from ref_dttm) when 6 then 1 when 0 then 2 else 0 end -
    case when extract(dow from ref_dttm) = extract(dow from first_action_dttm) then 2 else 0 end as weekends
from t_tickets

試着するsql fiddle demo

于 2013-08-27T08:25:05.040 に答える