查找日期范围内存在的天数

时间:2014-01-20 07:03:23

标签: sql oracle date date-range

+-------+-----------+------+----------------------+----------------------+
|RATE_ID|DESCRIPTION|CHARGE|FROM_DATE             |TO_DATE               |
+-------+-----------+------+----------------------+----------------------+
|1      |small      |100   |01/01/2014 12:00:00 AM|31/03/2014 12:00:00 AM|
+-------+-----------+------+----------------------+----------------------+
|2      |mediam     |200   |01/04/2014 12:00:00 AM|04/04/2014 12:00:00 AM|
+-------+-----------+------+----------------------+----------------------+
|3      |big        |300   |05/04/2014 12:00:00 AM|31/12/2014 12:00:00 AM|
+-------+-----------+------+----------------------+----------------------+

让上面的一个样本表在一个日期范围内收费,我会有一个输入就好了
start_date = to_date('30/mar/2014','dd/mon/yyyy')
end_date = to_date('05/apr/2014','dd/mon/yyyy')

因此输入日期包含在两天的收费100(rate_id = 1)中, 4天充电200和1天充电300和总共1300

是否有任何简单的方法可以找到给定范围内存在的天数,以便计算total_charge。目前我正在使用PL / SQL使用loop来查找存在。

整体而言: 从输入,

30 and 31st march belongs to small(100 charge) => 100* 2 = 200
1, 2, 3, 4 of april belongs to medium( 200 charge) => 200*4 = 800
5th april belongs to big ( 300 charge) => 300*1  = 300
so
the total:= 200 + 800 + 300 = 1300

提前致谢。

5 个答案:

答案 0 :(得分:0)

DATEDIFF()函数返回两个日期之间的时间。

SELECT DATEDIFF(day,'01-01-2014','31-03-2014') AS DiffDate

并考虑日期格式以获得正确的结果。

请参阅以下链接以获取更多信息 http://www.w3schools.com/sql/func_datediff.asp

答案 1 :(得分:0)

您可以使用CONNECT BY生成结束日期和开始日期之间的天数列表,并将此列表与费率列表结合起来:

with v_days as (
  SELECT TRUNC (to_date('2014-04-05', 'YYYY-MM-DD') - ROWNUM + 1) dt
  FROM DUAL 
  CONNECT BY ROWNUM <= (to_date('2014-04-05', 'YYYY-MM-DD') + 1 -
      to_date('2014-03-30', 'YYYY-MM-DD'))  
  ),
v_rates as (
  select 1 rate_id, 'small' rate,  100 charge, 
    to_date('2014-01-01', 'YYYY-MM-DD') start_date, 
    to_date('2014-03-31', 'YYYY-MM-DD') end_date 
  from dual union all
  select 2 rate_id, 'medium' rate, 200 charge, 
    to_date('2014-04-01', 'YYYY-MM-DD') start_date,  
    to_date('2014-04-04', 'YYYY-MM-DD') end_date from dual 
  union all
  select 3 rate_id, 'big' rate,    300 charge, 
    to_date('2014-04-05', 'YYYY-MM-DD') start_date, 
    to_date('2014-12-31', 'YYYY-MM-DD') end_date from dual
)  
select sum(charge) as total_charge from (
  select d.*, r.* from v_days d
  join v_rates r on d.dt >= r.start_date and d.dt <= r.end_date
  order by d.dt
)

说明:

  • v_days生成开始日期和结束日期之间的天数列表(每天一行)
  • v_rates只包含您提供的费率
  • 然后我们加入这两个子查询 - 如果给定日期属于费率的开始日期和结束日期之间的费率
  • 最后,我们只收取费用以获得总费用

答案 2 :(得分:0)

select sum(case
             when trunc(&start_date) <= trunc("to_date") AND
                  trunc(&end_date) >= trunc(from_date) then
              (least(trunc(&end_date), trunc("to_date")) -
              greatest(trunc(&start_date), trunc(from_date)) + 1) * charge
             else
              0
           end) total_charge
  from your_table;

最简单的方法是查找您的start_dateend_date是否跨越特定时期的边界(when中的case部分),然后计算它们之间的差异两个日期可以提供天数(+1是必需的,考虑开始日期和结束日期是否相同,您仍然需要收取1天的费用),然后将其乘以相应的费用。

如果包含日期范围的表格较大,请考虑将case条件移至where

select sum((least(trunc(&end_date), trunc("to_date")) -
           greatest(trunc(&start_date), trunc(from_date)) + 1)
            * charge) total_charge
  from your_table
 where trunc(&start_date) <= trunc("to_date")
   AND trunc(&end_date) >= trunc(from_date);

只要存在具有相同名称的转换函数,您就不希望使用列名“TO_DATE”。

答案 3 :(得分:0)

with w as (
  select 100 charge, date '2014-01-01' from_date, date '2014-03-31' to_date from dual union all
  select 200 charge, date '2014-04-01' from_date, date '2014-04-04' to_date from dual union all
  select 300 charge, date '2014-04-05' from_date, date '2014-12-31' to_date from dual
),
x as (
  select 
    date '2014-03-30' start_period,
    date '2014-04-05'   end_period
  from
    dual
)
select
sum(
  w.charge * 
    case when x.start_period <= w.  to_date and
              x.  end_period >= w.from_date
    then
       case when x.end_period > w.to_date
            then w.to_date
            else x.end_period
       end
            -
       case when x.start_period < w.from_date 
            then w.from_date
            else x.start_period
       end
       +1
    else
        0
    end
)   result
from
  w cross join x;

答案 4 :(得分:0)

AND TO_DATE(SYSDATE,&#39; dd / mm / yyyy&#39;)在截止日期(星期二,&#39; dd / mm / yyyy&#39;)和TO_DATE(END_DATE,&#39; dd /)之间月/年&#39;) 和到时(START_DATE,&#39; dd / mm / yyyy&#39;)&lt; = TO_DATE(SYSDATE,&#39; dd / mm / yyyy&#39;);