给定日期,选择月份包含的所有周数

时间:2015-01-28 14:23:52

标签: sql oracle oracle-apex

我有一个用于跟踪工作时间的ApEx应用程序。 我有一个看起来像这样的观点:

CREATE OR REPLACE VIEW HOURSDAYS
AS SELECT
 (MAX("TO_X") - MIN("FROM_X"))*24 - 
 (max(case when PROJECT_ID = 999 then to_x else to_date('01012000','DDMMYYYY') end) -
  max(case when PROJECT_ID = 999 then from_x else to_date('01012000','DDMMYYYY') end))*24 AS TIME_SPENT,
 DAY,
 PERSON_ID
 FROM ATTENDANCE_HOURS
 GROUP BY PERSON_ID, DAY
 ORDER BY DAY DESC

我需要每周的小时数。所以我有这个:

SELECT TO_CHAR(DAY,'IW'), MIN(DAY), MAX(DAY), SUM(TIME_SPENT)
FROM HOURSDAYS
WHERE PERSON_ID = (SELECT ID FROM ATTENDANCE_PEOPLE WHERE MAIL_SSO = V('APP_USER') AND ROLE = 0) AND
EXTRACT (YEAR FROM DAY) = EXTRACT (YEAR FROM TO_DATE(:P100_DATE_PICKER,'DD-MON-RR')) 
GROUP BY TO_CHAR(DAY,'IW')
ORDER BY TO_CHAR(DAY,'IW') ASC 

现在好玩的开始了:我有一个页面项目P100_DATE_PICKER,我只需要显示那些有>的周。属于我使用日期选择器选择的那个月的0天。 例如,对于1.1.2015,我只想显示第1,2,3,4,5周。 24.3.2015:9,10,11,12,13,14。

如果有人对我为什么这样做感兴趣,那就是验证 - 每周的工作时数不能超过20/32,具体取决于你的合约类型。

4 个答案:

答案 0 :(得分:1)

你可以这样做:

where day >= trunc(trunc(TO_DATE(:P100_DATE_PICKER,'DD-MON-RR'), 'MM'),'IW')
  and day <  trunc(last_day(TO_DATE(:P100_DATE_PICKER,'DD-MON-RR')),'IW') + 7

第一行以trunc开头到MM,它为您提供了约会的第一天。然后trunc再次向IW提供包含每月第一天的星期一星期一的日期。

第二行使用last_day来获取您所在日期的最后一天。然后truncIW获取 周的星期一,添加7天后获取星期一。然后使用<而非<=,您将获得所需的结果。

另外,我建议您不要按TO_CHAR(DAY,'IW')进行分组和排序,而是使用TRUNC(DAY,'IW')进行分组和排序。否则你可能会在新的一年左右遇到问题,因为你的代码在显示2014年12月的周数时必须显示2014年的49到52年以及2015年的第1周。如果你使用TO_CHAR那么在第49周至第52周之前,第1周将被错误地分类。

同样,在使用ISO周时,请勿使用EXTRACT(YEAR FROM ...)甚至TO_CHAR(...,'YYYY')。由于日期'2014-12-31'属于ISO第1周2015年,因此有一个特殊的日期格式字符串'IYYY',它为ISO周提供正确的年份。试一试,看看'YYYY''IYYY'之间的区别。

答案 1 :(得分:1)

这不会回答你的所有问题。这是根据您问题的主题行从给定日期开始的周计算的快速示例。请复制/粘贴以查看结果。此外,这里是检查周数的链接:

http://www.epochconverter.com/date-and-time/weeknumbers-by-year.php

SELECT given_date
 , end_date
 , TRUNC(calc_start_date, 'iw')                  wk_starts  
 , TRUNC(calc_start_date, 'iw') + 7 - 1/86400    wk_ends 
 , TO_CHAR(calc_start_date, 'iw')                wk_number
 , calc_start_date
FROM 
(
 SELECT trunc(sysdate, 'mm')                     given_date
 , trunc(sysdate, 'mm')-7 + LEVEL*7 AS      calc_start_date
 , Last_Day(trunc(SYSDATE, 'mm'))           end_date
FROM dual
CONNECT BY LEVEL <= ROUND((trunc(last_day(sysdate)) - trunc(sysdate, 'mm')+7)/7) -- number of weeks --
)
/
GIVEN DATE  END DATE    WK_STARTS     WK_ENDS                 WK NUMBER
-------------------------------------------------------------------------
1/1/2015    1/31/2015   12/29/2014    1/4/2015  11:59:59 PM   01
1/1/2015    1/31/2015   1/5/2015      1/11/2015 11:59:59 PM   02
1/1/2015    1/31/2015   1/12/2015     1/18/2015 11:59:59 PM   03
1/1/2015    1/31/2015   1/19/2015     1/25/2015 11:59:59 PM   04
1/1/2015    1/31/2015   1/26/2015     2/1/2015  11:59:59 PM   05

答案 2 :(得分:0)

实现最后一部分的最佳方法是拥有一个包含以下列的日历表

日期,日,例如星期一,月,季,年,星期

然后,对于给定日期,您只需选择属于该月份的所有周。

这允许您定义weekNo以使其适合公司环境。例如,偶尔您可能会获得53周的年度,特别是如果他们运行4-4-5个会计期间

答案 3 :(得分:0)

with days as (
  select 
      to_number(to_char(trunc(to_date('2015-03-24', 'yyyy-MM-dd'), 'month'), 'WW')) w1, 
      to_number(to_char(last_day(to_date('2015-03-24', 'yyyy-MM-dd')), 'WW')) w2 
    from dual)
select w1+level-1 week from days 
  connect by level <= w2-w1+1

子查询days给出最小和最长周,查询connect by返回这些值之间的数字。请将示例日期替换为:P100_DATE_PICKER。