- 确定一年是否是闰年
- 确定一年内的天数
- 从日期中提取时间的各部分
- 确定某个月的第一天和最后一天
- 确定一年内属于周内某天的所有日期
- 确定某月内第一个和最后一个周内某天的日期
- 创建日历
- 列出一年中每个季度的开始日期和结束日期
- 确定某个给定季度的开始日期和结束日期
- 填充丢失的日期
- 按照给定的时间单位进行查找
- 使用日期的特殊部分比较记录
- 识别重叠的日期范围
1.确定一年是否是闰年
方案:检查2月最后一天是29,确定是否是闰年
db2: with x(dy,mth) as (
select dy, month(dy) from (
select (current_date - dayofyear(current_date) days +1 days)+1 months as dy from t1
) tmp1 union all
select dy+1 days,mth from x where month(dy+1 day)=mth
)
select max(day(dy)) from x;
oracle : select to_char(last_day(add_months(tranc(sysdate,'y'),1)),'DD') from t1;
postgresql: select max(to_char(tmp2.dy+x.id,'DD')) as dy from (
select dy,to_char(dy,'MM') as mth from (
select cast(cast(date_tranc('year',current_date) as date)+ interval '1 month' as date) as dy from t1
)tmp1
)tmp2,generate_series(0,29) x(id)
where to_char(tmp2.dy+x.id,'MM') = tmp2.mth;
mysql: select day(last_day(date_add(date_add(date_add(current_date,interval -dayofyear(current_date) day),interval 1 day),interval 1 month))) dy from t1;
sqlserver: with x (dy,mth) as (
select dy,month(dy) from (
select dateadd(mm,1,(getdate()-datepart(dy,getdate()))+1) dy from t1
) tmp1 union all
select dateadd(dd,1,dy),mth from x where month(dateadd(dd,1,dy))=mth
)
select max(day(dy)) from x;
Note:估计会在存储过程中用吧
2.确定一年内的天数
db2: select day((curr_year+1 year)) - days(curr_year) from (
select (current_date -dayofyear(current_date) day +1 day) curr_year from t1
) x;
oracle: select add_months(trunc(sysdate,'y'),12) -tranc(sysdate,'y') from dual;
posgresql: select cast((curr_year + interval '1 year') as date) - curr_year from (
select cast(date_trunc('year',current_date) as date) as curr_year from t1
) x;
sqlserver: select datediff(d,curr_year,dateadd(yy,1,curr_year)) from (
select dateadd(d,-datepart(dy,getdate())+1,getdate()) curr_year from t1
) x;
mysql: select datediff((curr_year + interval 1 year),curr_year) from (
select adddate(current_date,-dayofyear(current_date)+1) curr_year from t1
) x;
Note:我不是太确定这个在数据库中会不会用到
3.从日期中提取时间的各部分
db2 : select hour(current_timestamp) hr, minute(current_timestamp) min,
second(current_timestamp) sec, day(current_timestamp) dy,
month(current_timestamp) mth, year(current_timestamp) yr from t1;
oracle: select to_number(to_char(sysdate,'hh24')) hour,
to_number(to_char(sysdate,'mi')) min,
to_number(to_char(sysdate,'ss')) sec,
to_number(to_char(sysdate,'dd')) day,
to_number(to_char(sysdate,'mm')) mth,
to_number(to_char(sysdate,'yyyy')) year from dual;
postgresql: select to_number(to_char(current_timestamp,'hh24'),'99') as hr,
to_number(to_char(current_timestamp,'mi'),'99') as min,
to_number(to_char(current_timestamp,'ss'),'99') as sec,
to_number(to_char(current_timestamp,'dd'),'99') as day,
to_number(to_char(current_timestamp,'mm'),'99') as mth,
to_number(to_char(current_timestamp,'yyyy'),'99') as yr
from t1;
mysql: select date_format(current_timestamp,'%k') hr,
date_format(current_timestamp,'%l') min,
date_format(current_timestamp,'%s') sec,
date_format(current_timestamp,'%d') dy,
date_format(current_timestamp,‘%m’) mon,
date_format(current_timestamp,'%Y') yr from t1;
sqlserver: select datepart(hour,getdate()) hr, depart(minute,getdate()) min,
datepart(second,getdate()) sec,depart(day,getdate()) dy,
datepart(month,getdate()) mon,depart(year,getdate()) yr from t1;
Note:这个操作是在where条件之前执行,要想改进效率必须先执行where条件,再执行日期的分解操作,用处还可以
4.确定某个月的第一天和最后一天
db2: select (current_date-day(current_date) day +1 day) firstday,
(current_date + 1 month - day(current_date) day) lastday from t1;
oracle: select tranc(sysdate,'mm') firstday,last_day(sysdate) lastday from dual;
postgresql: select firstday,cast(firstday + interval '1 month' -interval '1 day' as date) as lastday
from (select cast(date_trunc('month',current_date) as date) as firstday from t1);
mysql: select date_add(current_date,interval -day(current_date)+1 day) firstday,
last_day(current_date) lastday from t1;
sqlserver: select dateadd(day, -day(getdate())+1,getdate()) firstday,
dateadd(day,-day(getdate()),dateadd(month,1,getdate())) lastday from t1;
Note:这个不是很麻烦,就是其中的函数要清楚
5.确定一年内属于周内某一天的所有日期
db2: with x(dy,yr) as (
select dy,year(dy) yr from (
select (current_date-dayofyear(current_date) days + 1 days) as dy from t1
) tmp1 union all
select dy+1 days , yr from x where year(dy+1 day)=yr
)
select dy from x where dayname(dy)='Friday';
oracle: with x as (
select trunc(sysdate,'y')+level-1 dy from t1
connect by level <= add_months(trunc(sysdate,'y'),12)-trunc(sysdate,'y')
)
select * from x where to_char(dy,'dy')='fri';
postgresql: select cast(date_trunc('year',current_date) as date)+x.id as dy from generate_series(
0,(select cast(cast(date_trunc('year',current_date) as date)+ interval '1 years as date') -cast(date_trunc('year',current_date) as date))-1
) x(id) where to_char(cast(date_trunc('year',current_date) as date)+x.id,'dy')='fri';
mysql: select dy from (
select adddate(x.dy,interval t500.id-1 day) dy from (
select dy,year(dy) yr from (
select adddate(adddate(current_date,interval -dayofyear(current_date) day), interval 1 day) dy from t1) tmp1
) x,t500 where year(adddate(x.dy,interval t500.id-1 day))=x.yr
) tmp2 where dayname(dy)='Friday';
sqlserver: with x (dy,yr) as (
select dy,year(dy) yr from (
select getdate()-datepart(dy,getdate())+1 dy from t1
) tmp1 union all
select dateadd(dd,1,dy),yr from x where year(dateadd(dd,1,dy))=yr
)
select x.dy from x where datename(dw,x.dy)='Friday' option (maxrecursion 400);
Note:这个我也不是很确定有没有用,除非是在确定每年交易日期的时候有用。例如查询某一个日期是不是交易日
6.确定某月内第一个和最后一个‘周内某天的日期’
db2: with x (dy,mth,is_monday) as (
select dy,month(dy),case when dayname(dy)='Monday' then 1 else 0 end from (
select (current_date-day(current_date) day +1 day) dy from t1
) tmp1 union all
select (dy+1 day),mth,case when dayname(dy+1 day)='Monday' then 1 else 0 end
from x where month(dy + 1 day)=mth
)
select min(dy) first_monday,max(dy) last_monday from x where is_monday=1;
oracle: select next_day(trunc(sysdate,'mm')-1,'MONDAY') first_monday,
next_day(last_day(trunc(sysdate,‘mm’))-7,'MONDAY') last_monday
from dual;
postgresql: select first_monday,cast to_char(first_monday+28,'mm')
when mth then first_monday+28
else first_monday+21
end as last_monday
from (
select case sign(cast(to_char(dy,'d') as integer)-2)
when 0 then dy
when -1 then dy+abs(cast(to_char(dy,'d') as integer)-2)
when 1 then (7-(cast(to_char(dy,'d') as integer)-2))+dy
end as first_monday,mth from (
select cast(date_trunc('month',currnt_date) as date) as dy,
to_char(currnt_date,'mm') as mth from t1
) x
) y;
mysql: select first_monday,case month(adddate(first_monday,28))
when mth then adddate(first_monday,28)
else adddate(first_monday,21)
end last_monday
from (
select case sign(dayofweek(dy)-2)
when 0 then dy
when -1 then adddate(dy,abs(dayofweek(dy)-2))
when 1 then adddate(dy,(7-(dayofweek(dy)-2)))
end first_monday,mth from (
select adddate(adddate(currnt_date,-day(currnt_date)),1) dy
month(currnt_date) mth from t1
) x
) y;
sqlserver : with x (dy,mth,is_monday) as (
select dy,mth,case when datepart(dw,dy) =2
then 1 else 0 end from (
select dateadd(day,1,dateadd(day,-day(getdate()),getdate())) dy
month(getdate()) mth from t1
) tmp1 union all
select dateadd(day,1,dy),mth,case when datepart(dw,dateadd(day,1,dy))=2
then 1 else 0 end
from x where month(dateadd(day,1,dy))=mth
)
select min(dy) first_monday,max(dy) last_monday from x where is_monday=1;
Note:这个我能想到的是用来计算母亲节或者是父亲节,其他的用途我没想到
7.创建日历
db2:
with x(dy,dm,mth,dw,wk) as (
select (current_date-day(current_date) day + 1 day) dy,
day(current_date-day(current_date) day +1 day) dm,
month(current_date) mth,
dayofweek(current_date-day(current_date) day + 1 day) dw,
week_iso(current_date-day(current_date) day + 1 day) wk
from t1 union all
select dy+1 day,day(dy+1 day),mth,dayofweek(dy+1 day),week_iso(dy+1 day)
from x where month(dy+1 day)=mth
)
select max(case dw when 2 then dm end) as Mo,
max(case dw when 3 then dm end) as Tu,
max(case dw when 4 then dm end) as We,
max(case dw when 5 then dm end) as Th,
max(case dw when 6 then dm end) as Fr,
max(case dw when 7 then dm end) as Sa,
max(case dw when 1 then dm end) as su
from x group by wk order by wk;
oracle:
with x as (
select * from (
select to_char(trunc(sysdate,'mm')+level-1,'iw') wk,
to_char(trunc(sysdate,'mm')+level-1,'dd') dm,
to_number(to_char(trunc(sysdate,'mm')+level-1,'d')) dw,
to_char(trunc(sysdate,'mm')+level-1,'mm') curr_mth,
to_char(sysdate,'mm') mth
from dual connect by level<=31
) where curr_mth=mth
)
select max(case dw when 2 then dm end) as Mo,
max(case dw when 3 then dm end) as Tu,
max(case dw when 4 then dm end) as We,
max(case dw when 5 then dm end) as Th,
max(case dw when 6 then dm end) as Fr,
max(case dw when 7 then dm end) as Sa,
max(case dw when 1 then dm end) as su
from x group by wk order by wk;
postgresql:
select max(case dw when 2 then dm end) as Mo,
max(case dw when 3 then dm end) as Tu,
max(case dw when 4 then dm end) as We,
max(case dw when 5 then dm end) as Th,
max(case dw when 6 then dm end) as Fr,
max(case dw when 7 then dm end) as Sa,
max(case dw when 1 then dm end) as su
from (
select * from (
select cast(date_trunc('month',current_date) as date)+x.id,
to_char(cast(date_trunc('month',current_date) as date)+x.id,'iw') as wk,
to_char(cast(date_trunc('month',current_date) as date)+x.id,'dd') as dm,
cast(to_char(cast(date_trunc('month',current_date) as date)+x.id,'d') as integer) as dw,
to_char(cast(date_trunc('month',current_date) as date)+x.id,'mm') as curr_mth,
to_char(current_date,'mm') as mth
from generate_series(0,31) x(id)
) x where mth=curr_mth
) y group by wk order by wk;
mysql:
select max(case dw when 2 then dm end) as Mo,
max(case dw when 3 then dm end) as Tu,
max(case dw when 4 then dm end) as We,
max(case dw when 5 then dm end) as Th,
max(case dw when 6 then dm end) as Fr,
max(case dw when 7 then dm end) as Sa,
max(case dw when 1 then dm end) as su
from (
select date_format(dy,'%u') wk,
date_format(dy,'%d') dm,
date_format(dy,'%w')+1 dw
from (
select adddate(x.dy,t500.id-1) dy, x.mth from (
select adddate(current_date,-dayofmonth(current_date)+1) dy,
date_format(adddate(current_date,-dayofmonth(current_date)+1),'%m') mth
from t1
) x,t500 where t500.id<=31 and date_format(adddate(x.dy,t500.id-1),'%m')=x.mth
) y
) z group by wk order by wk;
sqlserver:
with x(dy,dm,mth,dw,wk) as (
select dy,day(dy) dm,datepart(m,dy) mth,datepart(dw,dy) dw,
case wgeb datepart(dw,dy)=1 then datepart(ww,dy)-1
else datepart(ww,dy) end wk
from (
select dateadd(day,-day(getdate())+1,getdate()) dy from t1
) x union all
select dateadd(d,1,dy),day(dateadd(d,1,dy)),mth,datepart(dw,dateadd(d,1,dy)),
case when datepart(dw,dateadd(d,1,dy))=1 then datepart(wk,dateadd(d,1,dy))-1
else datepart(wk,dateadd(d,1,dy)) end
from x where datepart(m,dateadd(d,1,dy))=mth
)
select max(case dw when 2 then dm end) as Mo,
max(case dw when 3 then dm end) as Tu,
max(case dw when 4 then dm end) as We,
max(case dw when 5 then dm end) as Th,
max(case dw when 6 then dm end) as Fr,
max(case dw when 7 then dm end) as Sa,
max(case dw when 1 then dm end) as su
from x group by wk order by wk;
Note:在数据库中输出日历,开眼界了,虽然也不知道这个有什么用
8.列出一年中每一个季度的开始日期和结束日期
db2:
select quarter(dy-1 day) QTR,dy-3 month Q_start,dy-1 day Q_end
from (
select (current_date-(dayofyear(current_date)-1) day +(rn*3) month) dy
from (
select row_number()over() rn from emp fetch first 4 rows only
)x
)y;
oracle:
select rownum qtr,
addmonths(trunc(sysdate,'y'),(rownum-1)*3) q_start,
addmonths(trunc(sysdate,'y'),rownum*3)-1 q_end
from emp where rownum<=4;
postgresql:
select to_char(dy,'Q') as QTR,
date(date_trunc('month',dy)-(2*interval '1 month')) dy as Q_end
from (
select date(dy+((rn*3)*interval '1 month'))-1 as dy from (
select rn,date(date_trunc('year',current_date)) as dy
from generate_series(1,4) gs(rn)
) x
) y ;
mysql:
select quarter(adddate(dy,-1)) QTR,
date_add(dy,interval -3 month) Q_start,
adddate(dy,-1) Q_end from (
select date_add(dy,interval (3*id) month) dy from (
select id,
adddate(current_date,-dayofyear(current_date)+1) dy
from t500 where id<=4
) x
) y;
sqlserver:
with x (dy,cnt) as (
select adteadd(d,-(datepart(dy, getdate())-1),getdate()),1 from t1
union all
select dateadd(m,3,dy),cnt+1 from x where cnt+1<=4
)
select datepart(q,dateadd(d,-1,dy)) QTR,
dateadd(m,-3,dy) Q_start,
date_add(d,-1,dy) Q_end from x order by 1;
Note:这个可用在按照季度统计数据的时候
9.确定某个给定季度的开始日期和结束日期
db2:
select (q_end-2 month) q_start,
(q_end+1 month)-1 day q_end
from (
select date(substr(cast(yrq as char(4)),1,4)
||'-'||
rtrim(cast(mod(yrq,10)*3 as char(2)))
||'-1') q_end from (
select 20181 yrd from t1 union all
select 20182 yrd from t1 union all
select 20183 yrd from t1 union all
select 20184 yrd from t1
) x
) y;
oracle:
select add_months(q_end,-2) q_start,last_day(q_end) q_end from (
select to_date(substr(yrq,1,4) || mod(yrq,10)*3,'yyyymm') q_end from (
select 20181 yrd from dual union all
select 20182 yrd from dual union all
select 20183 yrd from dual union all
select 20184 yrd from dual
) x
) y ;
postgresql:
select date(q_end-(2*interval '1 month')) as q_start,
date(q_end+interval '1 month' - interval '1 day') as q_end
from (
select to_date(substr(yrd,1,4)||mod(yrd,10)*3,'yyyymm') as q_end from (
select 20181 yrd from t1 union all
select 20182 yrd from t1 union all
select 20183 yrd from t1 union all
select 20184 yrd from t1
) x
) y ;
mysql:
select date_add(adddate(q_end,-day(q_end)+1),interval -2 month) q_start,q_end from (
select last_day(str_to_date(concat(substr(yrd,1,4),mod(yrd,10)*3),'%Y%m')) q_end from (
select 20181 yrd from t1 union all
select 20182 yrd from t1 union all
select 20183 yrd from t1 union all
select 20184 yrd from t1
)
)
sqlserver:
select dateadd(m,-2,q_end) q_start.dateadd(d,-1,dateadd(m,1,q_end)) q_end from (
select cast(substring(cast(yrd as varchar),1,4)
+'-'+cast(yrd%10*3 as varchar)
+'-1' as datetime) q_end from (
select 20181 yrd from t1 union all
select 20182 yrd from t1 union all
select 20183 yrd from t1 union all
select 20184 yrd from t1
) x
) y;
Note:标准的查询
10.填充丢失的日期
db2:
with x (start_date,end_date) as (
select (min(hiredate)-dayofyear(min(hiredate)) day +1 day) start_date,
(max(hiredate)-dayofyear(max(hiredate)) day +1 day) +1 year end_date
from emp union all
select start_date+1 month,end_date from x where (start_date+1 month)<end_date
)
select x.start_date mth,count(e.hiredate) num_hired from x
left join emp e on (x.start_date=(e.hiredate-(day(hiredate)-1) day))
group by x.start_date order by 1;
oracle:
with x as (
select add_months(start_date,level-1) start_date from (
select min(trunc(hiredate,'y')) start_date,
add_months(max(trunc(hiredate,'y')),12) end_date
from emp
) connect by level<=months_between(end_date,start_date)
)
select x.start_date MTH,count(e.hiredate) num_hired
from x, emp e where x.start_date=trunc(e.hiredate(+),'mm')
group by x.start_date order by 1;
postgresql:
create view v as
select cast(extract(year from age(last_month,first_month))*12-1 as interger) as mths from (
select cast(date_trunc('year',min(hiredate)) as date) as first_month,
cast(cast(date_trunc('year',max(hiredate)) as date)+ interval '1 year' as date) as last_month
from emp
) x
select y.mth,count(e.hiredate) as num_hired from (
select cast(e.start_date+(x.id*interval '1 month') as date) as mth
from generate_series(0,(select mths from v)) x(id),(
select cast(date_trunc('year',min(hiredate)) as date) as start_date from emp
) e
) y left join emp e on (y.mth=date_trunc('month',e.hiredate)) group by y.mth order by 1;
mysql:
select x.mth,count(e.hiredate) num_hired from (
select date_add(min_hd,interval t500.id-1 month) mth from (
select min_hd,date_add(max_hd,interval 11 month) mth from (
select adddate(min(hiredate),-dayofyear(min(hiredate))+1) min_hd,
adddate(max(hiredate),-dayodyear(max(hiredate))+1) max_hd
from emp
) x
) y,t500 where date_add(min_hd,interval t500.id-1 month)<=max_hd
) z left join emp e on (z.mth=adddate(date_add(last_day(e.hiredate),interval -1 month),1))
group by z.mth order by 1;
sqlserver:
with x (start_date,end_date) as (
select (min(hiredate)-datepart(dy,min(hiredate))+1) start_date,
dateadd(yy,1,(max(hiredate)-datepart(dy,max(hiredate))+1)) end_date
from emp union all
select dateadd(mm,1,start_date),end_date from x
where dateadd(mm,1,start_date)<end_date
)
select x.start_date mth,count(e.hiredate) num_hired
from x left join emp e
on (x.start_date=dateadd(dd,-day(e.hiredate)+1,e.hiredate))
group by x.start_date order by 1;
Note:按照季度统计数据
11.按照给定的时间单位进行查找
db2/mysql:
select ename from emp
where monthname(hiredate) in ('December','February')
or dayname(hiredate)='Tuesday';
oracle/postgresql:
select ename from emp
where rtrim(to_char(hiredate,'month')) in ('December','February')
or rtrim(to_char(hiredate,'day'))='tuesday';
sqlserver:
select ename from emp
where datename(m,hiredate) in ('December','February')
or datename(dw,hiredate) = 'Tuesday';
Note:按照日期的属性来查找
12.使用日期的特殊部分比较记录
db2:
select a.ename,b.ename from emp a,emp b
where (dayofweek(a.hiredate),monthname(a.hiredate))=
(dayofweek(b.hiredate),monthname(b.hiredate))
and a.empno<b.empno order by a.ename;
oracle/postgresql:
select a.ename,b.ename from emp a,emp b
where to_char(a.hiredate,'DMON')=to_char(b.hiredate,'DMON')
and a.empno<b.empno order by a.ename;
mysql:
select a.ename,b.ename from emp a, emp b
where date_format(a.hiredate,'%w%M')=date_format(b.hiredate,'%w%M')
and a.empno<b.empno order by a.ename;
sqlserver:
select a.ename,b.ename from emp a, emp b
where datename(dw,a.hiredate)=datename(dw,b.hiredate)
and datename(m,a.hiredate)=datename(m,b.hiredate)
and a.empno=b.empno order by a.ename;
Note:按照日期的属性来进行比较
13.识别重叠的日期范围
select a.empno,a.ename,b.project_id,a.project_id
from emp_project a,emp_project b
where a.empno=b.empno
and b.project_start>=a.project_start
and b.project_start<=a.project_end
and b.project_id!=a.project_id;
Note:同一张表中的范围比较