2012-01-17 6 views
2

오케이, 나는 SQL에서 Excel의 networkdays 기능을 에뮬레이션 할 가능성에 대해 많은 책을 읽었으며 다음과 같은 결론을 얻었습니다. 가장 쉬운 해결책은 근무일 또는 비 근무일을 표시하는 캘린더 테이블을 만드는 것입니다. 그러나 사정상 통제 할 수없는 사정으로 인해 우리는 그런 고급 스러움에 접근 할 수 없으며 가까운 장래에 언제든지 할 수있는 일은 없을 것입니다.오라클에 달력 테이블이없는 날짜 사이의 공휴일을 포함한 계산 일 SQL

현재 나는 의심 할 여지없이 SQL에서 작동하는 SQL의 끔찍한 비효율적 인 쿼리를 함께 관리합니다. 즉, 한 번에 하나의 클라이언트 레코드에서만 작동합니다. A)가 나는이 내 시간을 낭비 중지해야 또는 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의 대답은 천천히 불구하고 완벽하게 작동합니다 (I만큼 주어진 기대했던 비록이 선호하는 솔루션이 아니다) - 도전이 지금 나 기존 보고서에이 통합에있다!

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

달력 데이터를 저장할 테이블을 만들 수없는 경우 데이터베이스에서 내 응답의 CTE와 비슷한 달력 테이블을 모방하는보기를 만들 수 있습니까? –

+0

@ MarkBannister : 아마도 이전에 생각했던 것과 같은 것을 만들려고했으나 원하는 결과를 얻지 못했습니다. – bawpie

답변

3

몇 가지 방법이 있습니다. 아마도 가장 간단한과 같이, 오라클의 connect by 구문을 기반으로 가상 달력 테이블을 생성하는 CTE를 만든 다음 Assesments 테이블에 가입 할 수 있습니다

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 

이 날짜로 채워 가상 테이블을 생성합니다 2000 년 1 월 1 일부터 현재 날짜 이후 10 년까지, 모든 주말은 휴무일로 표시되고 두 번째 in 조항 (즉, 2011 년 12 월 27 일까지)에 지정된 모든 요일은 휴무일로 표시됩니다.

공휴일이 쿼리에 하드 코드 된 모든 메서드는 새로운 공휴일이 정의 될 때마다이 접근법을 사용하는 모든 쿼리에 해당 날짜가 추가되어야한다는 단점이 있습니다.

+0

Thanks Mark - 나는 이것을 시험해 보았습니다.하지만 'working_day'필드는 근무일이 아닌 날짜 사이의 모든 날에 걸쳐 작동하므로 제대로 작동하지 않는 것 같습니다. 어쨌든 주위에 바이올린을 갖게 될 것입니다. 도움을 다시 한번 감사드립니다! – bawpie

+0

@bawpie : 어떤 날짜 범위를 사용 했습니까? (덧붙여서'sum (working_day)', ** ** count (working_day)가 아닌'note). –

+0

내가 게시 한 쿼리에서 하나의 레코드에 대해 실행했습니다. 2011 년 11 월 11 일 및 2013 년 1 월 13 일 쿼리를 사용하여 동일한 레코드에 대해 실행하면 (게시 된 내용과 동일하지 않음) 66 일이 반환됩니다. 나는 그것이 주말의 날 이름 (듀얼 경우는 소문자 인 것 같지만 계산되지 않은 실제 휴일 날짜는 확실하지 않음)의 경우와 관련이있을 수 있다고 생각합니다. – bawpie

0

오라클에서 캘린더 테이블을 사용할 수 없다면 Excel로 내보내기하는 것이 더 나을 것입니다. 무력은 항상 효과가 있습니다.

Networkdays() "start_date와 end_date 사이의 전체 근무일 수를 반환하며, 근무일에는 휴일과 주말을 제외합니다."

주말 제외는 매우 간단합니다. 7 일마다 두 주말이 포함됩니다. 당신은 남은 시절을 돌봐야 할 것입니다.

휴일은 다른 이야기입니다. 당신은 그것들을 저장하거나 인자로 전달해야합니다. 당신이 그들을 저장할 수 있다면, 당신은 달력 테이블에 그들을 저장하고, 당신의 문제는 끝날 것입니다. 그러나 당신은 그것을 할 수 없습니다.

그래서 인자로 전달하려고합니다. 내 머리 꼭대기에서 - 그리고 나는 아직 아침에 차를 마시지 않았습니다 - 나는 공통 테이블 식 또는 저장 프로 시저에 대한 래퍼를 고려할 것입니다.

+0

감사합니다. 이미 Excel을 사용하고 있습니다. 그러나 사용자가 액세스 할 수있는 곳으로 보고서를 보급하고 Google의 개입없이 보고서를 새로 고치려고합니다. SQL을 사용하는 시간 척도와 같은 작업은 체리 위에. 그것이 할 수없는 경우에, 우리는 엑셀을 사용하는 것을 계속할 것이다, 다만 초조 한 조금이다. 이론적으로 우리는 사용자에게 데이터를 복사하여 시간 척도를 계산하는 템플릿을 제공 할 수 있지만, 그 단계를 완전히 없애는 것이 좋을 것입니다. – bawpie

+0

@bawpie : [Excel 내에서 데이터베이스에 쿼리 할 수 ​​있습니다] (http://www.exceluser.com/explore/msquery1_1.htm). –