繁体   English   中英

SQL查询构建:如何分解不同行中的时间段

[英]SQL Query building: howto decompose periods of time in different rows

如何构建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

谢谢

对于这样的计算,您可以使用date dimension -一个表格,其中将您网域中的所有日期都包含为单行( 例如,请参见)。

在数据库中有了日期维度后,事情就变得简单了:

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

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

SQL小提琴

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
)

结果

|  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 |

使用函数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演示

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM