2012-01-17 9 views
2

これで、SQLでExcelのnetworkdays関数をエミュレートする可能性についてかなり読んだことがあります。はるかに簡単な解決策は、就業日または休業日のフラグを立てるカレンダーテーブルを持つことです。しかし、私のコントロールできない状況のせいで、私たちはそのような高級品にアクセスすることはできず、いつでも近い将来にはそうすることはできません。oracleのカレンダー表を使用しない日付間の休日を含む勤務日の計算SQL

現在、私は間違いなく恐ろしい非効率なクエリをSQLで処理しています。これは、一度に1つのクライアントレコードに対してのみ機能します。 )私はこの上で私の時間を無駄に停止する必要がありますまたはb)それが、これは複数のクライアントのために働くことを得ることが可能である場合

SELECT O_ASSESSMENTS.ASM_ID, 
     O_ASSESSMENTS.ASM_START_DATE, 
     O_ASSESSMENTS.ASM_END_DATE, 
     sum(CASE 
       When TO_CHAR(O_ASSESSMENTS.ASM_START_DATE + rownum -1,'Day') 
        = 'Sunday ' THEN 0 
       When TO_CHAR(O_ASSESSMENTS.ASM_START_DATE + rownum -1,'Day') 
        = 'Saturday ' THEN 0 
       WHEN O_ASSESSMENTS.ASM_START_DATE + rownum - 1 
        IN ('03-01-2000','21-04-2000','24-04-2000','01-05-2000','29-05-2000','28-08-2000','25-12-2000','26-12-2000','01-01-2001','13-04-2001','16-04-2001','07-05-2001','28-05-2001','27-08-2001','25-12-2001','26-12-2001','01-01-2002','29-03-2002','01-04-2002','06-04-2002','03-06-2002','04-06-2002','26-08-2002','25-12-2002','26-12-2002','01-01-2003','18-04-2003','21-04-2003','05-05-2003','26-05-2003','25-08-2003','25-12-2003','26-12-2003','01-01-2004','09-04-2004','12-04-2004','03-05-2004','31-05-2004','30-08-2004','25-12-2004','26-12-2004','27-12-2004','28-12-2004','01-01-2005','03-01-2005','25-03-2005','28-03-2005','02-05-2005','30-05-2005','29-08-2005','27-12-2005','28-12-2005','02-01-2006','14-04-2006','17-04-2006','01-05-2006','29-05-2006','28-08-2006','25-12-2006','26-12-2006','02-01-2007','06-04-2007','09-04-2007','07-05-2007','28-05-2007','27-08-2007','25-12-2007','26-12-2007','01-01-2008','21-03-2008','24-03-2008','05-05-2008','26-05-2008','25-08-2008','25-12-2008','26-12-2008','01-01-2009','10-04-2009','13-04-2009','04-05-2009','25-05-2009','31-08-2009','25-12-2009','28-12-2009','01-01-2010','02-04-2010','05-04-2010','03-05-2010','31-05-2010','30-08-2010','24-12-2010','27-12-2010','28-12-2010','31-12-2010','03-01-2011','22-04-2011','25-04-2011','29-04-2011','02-05-2011','30-05-2011','29-08-2011','26-12-2011','27-12-2011') 
        THEN 0 
       ELSE 1 
      END)-1 AS Week_Day 
From O_ASSESSMENTS, 
    ALL_OBJECTS 
WHERE O_ASSESSMENTS.ASM_QSA_ID IN ('TYPE1') 
    AND O_ASSESSMENTS.ASM_END_DATE >= '01/01/2012' 
    AND O_ASSESSMENTS.ASM_ID = 'A00000' 
    AND ROWNUM <= O_ASSESSMENTS.ASM_END_DATE-O_ASSESSMENTS.ASM_START_DATE+1 
GROUP BY 
     O_ASSESSMENTS.ASM_ID, 
     O_ASSESSMENTS.ASM_START_DATE, 
     O_ASSESSMENTS.ASM_END_DATE 

基本的に、私は思ったんだけど?どのポインタもありがとう!

編集:さらに明確化 - 私は既にExcelを使ってタイムスケールを作成していますが、問題の報告がエンドユーザーには何もせずに実行できるようにするため、レポートで実行できるのが理想ですさらなる操作。

編集:(私は同じくらい、それは好ましい解決策ではありません与えられた期待していたが)

MarkBannisterの答えはゆっくりで完璧に動作 - 現在の課題は、既存のレポートにこれを統合する私にあります!

with 
calendar_cte as (select 
to_date('01-01-2000')+level-1 calendar_date, 
case when to_char(to_date('01-01-2000')+level-1, 'day') in ('sunday ','saturday ') then 0 when to_date('01-01-2000')+level-1 in ('03-01-2000','21-04-2000','24-04-2000','01-05-2000','29-05-2000','28-08-2000','25-12-2000','26-12-2000','01-01-2001','13-04-2001','16-04-2001','07-05-2001','28-05-2001','27-08-2001','25-12-2001','26-12-2001','01-01-2002','29-03-2002','01-04-2002','06-04-2002','03-06-2002','04-06-2002','26-08-2002','25-12-2002','26-12-2002','01-01-2003','18-04-2003','21-04-2003','05-05-2003','26-05-2003','25-08-2003','25-12-2003','26-12-2003','01-01-2004','09-04-2004','12-04-2004','03-05-2004','31-05-2004','30-08-2004','25-12-2004','26-12-2004','27-12-2004','28-12-2004','01-01-2005','03-01-2005','25-03-2005','28-03-2005','02-05-2005','30-05-2005','29-08-2005','27-12-2005','28-12-2005','02-01-2006','14-04-2006','17-04-2006','01-05-2006','29-05-2006','28-08-2006','25-12-2006','26-12-2006','02-01-2007','06-04-2007','09-04-2007','07-05-2007','28-05-2007','27-08-2007','25-12-2007','26-12-2007','01-01-2008','21-03-2008','24-03-2008','05-05-2008','26-05-2008','25-08-2008','25-12-2008','26-12-2008','01-01-2009','10-04-2009','13-04-2009','04-05-2009','25-05-2009','31-08-2009','25-12-2009','28-12-2009','01-01-2010','02-04-2010','05-04-2010','03-05-2010','31-05-2010','30-08-2010','24-12-2010','27-12-2010','28-12-2010','31-12-2010','03-01-2011','22-04-2011','25-04-2011','29-04-2011','02-05-2011','30-05-2011','29-08-2011','26-12-2011','27-12-2011','01-01-2012','02-01-2012') then 0 else 1 end working_day 
from dual 
connect by level <= 1825 + sysdate - to_date('01-01-2000')) 
SELECT 
a.ASM_ID, 
a.ASM_START_DATE, 
a.ASM_END_DATE, 
sum(c.working_day)-1 AS Week_Day 
From 
O_ASSESSMENTS a 
join calendar_cte c 
on c.calendar_date between a.ASM_START_DATE and a.ASM_END_DATE 
WHERE a.ASM_QSA_ID IN ('TYPE1') 
and a.ASM_END_DATE >= '01/01/2012' 
GROUP BY  
a.ASM_ID, 
a.ASM_START_DATE, 
a.ASM_END_DATE 
+0

どうすればカレンダーテーブルを作成できないのですか? –

+0

カレンダーデータを保持するテーブルを作成できない場合は、データベース内にカレンダーテーブルを模倣するビューを作成できますか? –

+0

@ MarkBannister:おそらく、私はこれまで考えていたようなものを作り出そうとしましたが、望みの結果が得られませんでした。 – bawpie

答えて

3

これを行う方法はいくつかあります。

with calendar_cte as (
select to_date('01-01-2000')+level-1 calendar_date, 
     case when to_char(to_date('01-01-2000')+level-1, 'Day') 
       in ('Sunday ','Saturday ') then 0 
      when to_date('01-01-2000')+level-1 
       in ('03-01-2000','21-04-2000','24-04-2000','01-05-2000','29-05-2000','28-08-2000','25-12-2000','26-12-2000','01-01-2001','13-04-2001','16-04-2001','07-05-2001','28-05-2001','27-08-2001','25-12-2001','26-12-2001','01-01-2002','29-03-2002','01-04-2002','06-04-2002','03-06-2002','04-06-2002','26-08-2002','25-12-2002','26-12-2002','01-01-2003','18-04-2003','21-04-2003','05-05-2003','26-05-2003','25-08-2003','25-12-2003','26-12-2003','01-01-2004','09-04-2004','12-04-2004','03-05-2004','31-05-2004','30-08-2004','25-12-2004','26-12-2004','27-12-2004','28-12-2004','01-01-2005','03-01-2005','25-03-2005','28-03-2005','02-05-2005','30-05-2005','29-08-2005','27-12-2005','28-12-2005','02-01-2006','14-04-2006','17-04-2006','01-05-2006','29-05-2006','28-08-2006','25-12-2006','26-12-2006','02-01-2007','06-04-2007','09-04-2007','07-05-2007','28-05-2007','27-08-2007','25-12-2007','26-12-2007','01-01-2008','21-03-2008','24-03-2008','05-05-2008','26-05-2008','25-08-2008','25-12-2008','26-12-2008','01-01-2009','10-04-2009','13-04-2009','04-05-2009','25-05-2009','31-08-2009','25-12-2009','28-12-2009','01-01-2010','02-04-2010','05-04-2010','03-05-2010','31-05-2010','30-08-2010','24-12-2010','27-12-2010','28-12-2010','31-12-2010','03-01-2011','22-04-2011','25-04-2011','29-04-2011','02-05-2011','30-05-2011','29-08-2011','26-12-2011','27-12-2011') 
       then 0 
      else 1 
     end working_day 
from dual 
connect by level <= 36525 + sysdate - to_date('01-01-2000')) 
SELECT a.ASM_ID, 
     a.ASM_START_DATE, 
     a.ASM_END_DATE, 
     sum(c.working_day) AS Week_Day 
From O_ASSESSMENTS a 
join calendar_cte c 
    on c.calendar_date between a.ASM_START_DATE and a.ASM_END_DATE 
WHERE a.ASM_QSA_ID IN ('TYPE1') and 
     a.ASM_END_DATE >= '01/01/2012' -- and a.ASM_ID = 'A00000' 
GROUP BY 
     a.ASM_ID, 
     a.ASM_START_DATE, 
     a.ASM_END_DATE 

これは、日付が移入仮想テーブルが生成されますので、同様におそらく最も簡単なのは、Oracleのconnect by構文に基づいて、仮想カレンダーテーブルを生成CTEを作成し、Assesments、それをテーブルに参加するかもしれません2000年1月1日から現在の日付の10年後まで、すべての週末は休業日とし、2番目のin条項(すなわち2011年12月27日まで)に指定されているすべての日は休業日とする。

この方法(または休日の日付がクエリにハードコードされている方法)の欠点は、新しい休日の日付が定義されるたびに、このアプローチを使用するすべてのクエリでこれらの日付を追加する必要があることです。

+0

ありがとうマーク - これを試しましたが、 'working_day'フィールドは、就業日ではなく日付の間に終日働いているので正しく機能していないようです。とにかく周りのフィドルがあります、もう一度援助に感謝! – bawpie

+0

@bawpie:これに対してどの日付の範囲を試しましたか? (また、 'sum(working_day)'、** ** count(working_day)ではないことに注意してください。) –

+0

私はそれを1レコードに対して実行しました。 2011年7月11日および2013年1月13日クエリを使用して同じレコードに対して実行している(これはあなたが投稿したものと同じです)、66日を返します。私は、週末の日の名前(二重で小文字に見えますが、実際の休日の日付は計算されていないかどうかはわかりません)の場合とすることができると思います。 – bawpie

0

Oracleでカレンダーテーブルを使用できない場合は、Excelに書き出す方がよい場合があります。ブルートフォースは常に働きます。

Networkdays() "は、start_dateからend_dateまでの作業日数の合計を返します。作業日は、休日で識別された週末および休日を除外します。

週末を除くと、かなり簡単です。 7日ごとに週2日が含まれます。残された日にはちょっとした注意が必要です。

祝祭日は別の話です。それらを格納するか、引数として渡す必要があります。あなたがそれらを保存することができれば、あなたはカレンダーテーブルにそれらを保存し、あなたの問題は終わるでしょう。しかし、あなたはそれをすることはできません。

あなたは引数として渡すことを検討しています。私の頭の上から離れて - 今朝はまだお茶を持っていません - 私は共通のテーブル式やストアドプロシージャのラッパーを考えます。

+0

私はすでにこれを解決するためにExcelを使用していますが、ユーザーがアクセスできる場所にレポートを展開し、介入なしに更新することを検討しています.SQLを使用したタイムスケールのような作業は、上の桜。それができない場合、私たちは引き続きExcelを使用しますが、ちょっとイライラします。理論的には、データをコピーしてタイムスケールを作成するためのテンプレートをユーザーに提供することができますが、そのステップを完全に切り捨てるのが良いでしょう。 – bawpie

+0

@bawpie:あなたは[Excel内からデータベースに問い合わせる]ことができます(http://www.exceluser.com/explore/msquery1_1.htm)。 –

関連する問題