我正在尝试创建一个按周开始和结束列的表,它不会与月份转换重叠。以2016年1月为例,我希望结果如下:
Start End
1/1/2016 1/2/2016
1/3/2016 1/9/2016
1/10/2016 1/16/2016
1/17/2016 1/23/2016
1/24/2016 1/30/2016
1/31/2016 1/31/2016
我目前对查询的看法是(我希望第2和第3列中的记录相应排列):
DATES Wk_START_END MONTH_START_END
1/1/2016 1/1/2016
1/2/2016 1/2/2016
1/3/2016 1/3/2016
1/4/2016
1/5/2016
1/6/2016
1/7/2016
1/8/2016
1/9/2016 1/9/2016
1/10/2016 1/10/2016
1/11/2016
1/12/2016
1/13/2016
1/14/2016
1/15/2016
1/16/2016 1/16/2016
1/17/2016 1/17/2016
1/18/2016
1/19/2016
1/20/2016
1/21/2016
1/22/2016
1/23/2016 1/23/2016
1/24/2016 1/24/2016
1/25/2016
1/26/2016
1/27/2016
1/28/2016
1/29/2016
1/30/2016 1/30/2016
1/31/2016 1/31/2016 1/31/2016
此处的查询是:
SELECT trunc
(sysdate, 'YEAR')+rownum-1 DATES
--,to_char(trunc(sysdate,'YEAR') + rownum -1 ,'D') Day_Of_Wk
, CASE
WHEN to_char
(trunc
(sysdate, 'YEAR')+rownum-1, 'D') = '1' THEN trunc
(sysdate, 'YEAR')+rownum-1
WHEN to_char
(trunc
(sysdate, 'YEAR')+rownum-1, 'D') = '7' THEN trunc
(sysdate, 'YEAR')+rownum-1
ELSE NULL
END Wk_Start_End
, CASE
WHEN trunc
(sysdate, 'YEAR')+rownum-1 = TRUNC
(trunc
(sysdate, 'YEAR')+rownum-1, 'MONTH') THEN trunc
(sysdate, 'YEAR')+rownum-1
WHEN trunc
(sysdate, 'YEAR')+rownum-1 = Add_months
(TRUNC
(trunc
(sysdate, 'YEAR')+rownum-1, 'MONTH'), 1)-1 THEN trunc
(sysdate, 'YEAR')+rownum-1
END Month_Start_end
FROM all_objects
WHERE trunc
(sysdate, 'YEAR')+rownum <= Add_months
(trunc
(sysdate, 'YEAR'), 12)-1;
感谢任何帮助。谢谢!
答案 0 :(得分:1)
嗯。您似乎想要带有值的奇数行以及下一个非空值。我在想:
select dte as start_date, next_dte and end_date
from (select ao.*, rownum as seqnum, lead(dte) over (order by dates) as next_dte
from ((select dates, Wk_START_END as dte from all_objects ao) union all
(select dates, MONTH_START_END as dte from all_objects ao)
) t
where dte is not null
) t
where mod(seqnum, 2) = 1;
答案 1 :(得分:1)
以下是针对所有2016年日期执行此操作的查询。你希望,你可以为你的目的推断它。
基本方法是获取感兴趣范围内的所有日期(例如,2016年全部),然后按月/周分组。然后在每个组中获得min()
和max()
日期。
WITH dtes AS
(SELECT TO_DATE ('01-JAN-2016') + ROWNUM - 1 dte
FROM DUAL
CONNECT BY ROWNUM <= 365),
dtes_grouped_by_month_week AS
(SELECT dte,
DENSE_RANK () OVER (PARTITION BY NULL ORDER BY TO_CHAR (dte, 'IYYY-MM'), TO_CHAR (dte, 'IW')) month_week
FROM dtes)
SELECT MIN (dte) start_date,
MAX (dte) end_date
FROM dtes_grouped_by_month_week
GROUP BY month_week
ORDER BY month_week;
看看你的例子,你似乎希望星期日成为一周的第一天而不是星期一。在查询中可以轻松调整 - 只需在TO_CHAR
的{{1}}函数中添加+1即可。
答案 2 :(得分:1)
下面的查询从头开始 - 它不会使用您的任何代码(或其输出)。年份和月份在第一个CTE中进行了硬编码(顶部的WITH子句中的子因子查询);更有可能在您的应用程序中,您将排除名为inputs
的第一个CTE,并且您将y
和m
置于first_date
定义中的绑定变量中(同样在WITH子句)。
我使用了你的约定:一周开始于&#34;一周的第一天&#34; (在美国是星期日)并在本周的第7天结束。&#34;如果需要,可以通过NLS参数进行调整。
with
inputs ( y, m ) as (
select 2016, 1 from dual
),
first_date ( f_dt ) as (
select to_date(to_char(y, '0009') || '-' || to_char(m, '09'), 'yyyy-mm')
from inputs
),
mth_dates ( dt ) as (
select f_dt + level - 1 from first_date
connect by level <= last_day(f_dt) - f_dt + 1
),
start_dates ( dt, rn ) as (
select dt, row_number() over (order by dt)
from ( select dt from mth_dates where to_char(dt, 'd') = '1'
union
select min(dt) from mth_dates )
),
end_dates ( dt, rn ) as (
select dt, row_number() over (order by dt)
from ( select dt from mth_dates where to_char(dt, 'd') = '7'
union
select max(dt) from mth_dates )
)
select s.rn as week_nbr, s.dt as start_date, e.dt as end_date
from start_dates s inner join end_dates e on s.rn = e.rn;
WEEK_NBR START_DATE END_DATE
---------- ---------- ----------
1 2016-01-01 2016-01-02
2 2016-01-03 2016-01-09
3 2016-01-10 2016-01-16
4 2016-01-17 2016-01-23
5 2016-01-24 2016-01-30
6 2016-01-31 2016-01-31
OP的请求ADDED :
要生成整年的开始和结束日期,可以使用下面的查询。
with
inputs ( y ) as (
select 2016 from dual
),
first_date ( f_dt ) as (
select to_date(to_char(y, '0009') || '-01-01', 'yyyy-mm-dd')
from inputs
),
year_dates ( dt ) as (
select f_dt + level - 1 from first_date
connect by level <= add_months(f_dt, 12) - f_dt
),
start_dates ( dt, rn ) as (
select dt, row_number() over (order by dt)
from ( select dt from year_dates where to_char(dt, 'd') = '1'
or extract(day from dt) = 1 )
),
end_dates ( dt, rn ) as (
select dt, row_number() over (order by dt)
from ( select dt from year_dates where to_char(dt, 'd') = '7'
or extract(day from dt + 1) = 1 )
)
select s.dt as start_date, e.dt as end_date
from start_dates s inner join end_dates e on s.rn = e.rn;
进一步评论:我实际上更喜欢马修的答案。他的解决方案只是简单地将日子分组到正确的交叉点和#34;几个月和几周,并在这些组上使用max()
和min()
,无需加入。它比我的解决方案更好。
为了完整起见,我在下面复制了Matthew的解决方案,并进行了一些小改动。
首先,为了符合要求(和Matthew建议的那样),我在按周组成组时将{1}加1,所以星期几开始星期几,星期六结束。
其次,正如我在对马修答案的评论中所建议的那样,我使用&#34;月&#34;和&#34;周&#34;直接组成团体;不需要dte
。
第三,为了符合良好的编码习惯,我在第一次CTE中向dense_rank()
添加了明确的日期格式模型。
信用:@Matthew McPeak
to_date()