SQL Query构建:如何分解不同行的时间段

时间:2015-08-12 07:32:13

标签: sql oracle relational-database

如何构建SQL查询以分解某些句点,例如在几个月内。

数据库表:

id      fromdate         todate        value
--------------------------------------------
100     01.01.2015       01.03.2015    10

所需的查询结果:

id      fromdate         todate        value 
--------------------------------------------
100     01.01.2015       01.02.2015    5,25
100     01.02.2015       01.03.2015    4,75

其中值基于两个日期之间的天数,例如:

value(january) = 31(january nr of days) * 10(original value) / 59(total days) = 5,25

谢谢

3 个答案:

答案 0 :(得分:1)

对于这样的计算,您可以使用date dimension - 一个表格,其中包含您网域中的所有日期作为单行(请参阅example的内容)。

数据库中的日期维度变得简单了:

WITH data_by_date AS 
( -- Here we join dates to your periods to turn each row in 
  -- as many rows as there are days in the period.
  -- We also turn value field into value_per_day.
 SELECT
   d.date,
   d.month_year,  
   t.id,
   value / (t.todate - t.fromdate) as value_per_day
 FROM
   dim_date d INNER JOIN 
   my_table t ON d.date >= t.fromdate AND d.date < t.todate
)
SELECT -- Here we group by results by month.
  dd.id, 
  MIN(dd.date) as fromdate, 
  MAX(dd.date) as todate, 
  SUM(dd.value_per_day) as value 
FROM  data_by_date dd
GROUP BY dd.id, dd.month_year

答案 1 :(得分:1)

使用分层查询为每个条目生成月份列表:

SQL Fiddle

Oracle 11g R2架构设置

CREATE TABLE TEST (id, fromdate, todate, value ) AS
          SELECT 100, DATE '2015-01-01', DATE '2015-03-01', 10 FROM DUAL
UNION ALL SELECT 200, DATE '2014-12-22', DATE '2015-01-06', 30 FROM DUAL

查询1

SELECT ID,
       fromdate,
       todate,
       VALUE * ( todate - fromdate ) / ( maxdate - mindate ) AS value
FROM (
  SELECT ID,
         GREATEST( t.fromdate, m.COLUMN_VALUE ) AS fromdate,
         LEAST( t.todate, ADD_MONTHS( m.COLUMN_VALUE, 1 ) ) AS todate,
         t.fromdate AS mindate,
         t.todate AS maxdate,
         t.value
  FROM   TEST t,
         TABLE(
           CAST(
             MULTISET(
               SELECT  ADD_MONTHS( TRUNC( t.fromdate, 'MM' ), LEVEL - 1 )
               FROM    DUAL
               CONNECT BY
                       ADD_MONTHS( TRUNC( t.fromdate, 'MM' ), LEVEL - 1 ) < t.todate
             )
             AS SYS.ODCIDATELIST
           )
         ) m
)

<强> Results

|  ID |                   FROMDATE |                     TODATE |             VALUE |
|-----|----------------------------|----------------------------|-------------------|
| 100 |  January, 01 2015 00:00:00 | February, 01 2015 00:00:00 | 5.254237288135593 |
| 100 | February, 01 2015 00:00:00 |    March, 01 2015 00:00:00 | 4.745762711864407 |
| 200 | December, 22 2014 00:00:00 |  January, 01 2015 00:00:00 |                20 |
| 200 |  January, 01 2015 00:00:00 |  January, 06 2015 00:00:00 |                10 |

答案 2 :(得分:0)

使用函数add_months()和层次结构子查询为每个id生成句点:

select id, d1, d2, round(value*(d2-d1)/nod, 2) value 
  from (
    select id, value, todate-fromdate nod, add_months(fromdate, level-1) d1, 
           least(add_months(fromdate, level), todate) d2
      from data 
      connect by add_months(fromdate, level) <= trunc(add_months(todate, 1)-1) 
        and id = prior id and prior dbms_random.value is not null )

SQLFiddle demo