Create a time series from a list

I have some period data that look like this:

PName        DtFrom       DtTo          Amount
Period_1     2018-01-01   2018-01-10    100
Period_2     2018-01-03   2018-01-08    10
Period_3     2018-01-05   2018-01-12    1

I would like to get the following time series by adding the amounts that are inside the date frame of each period:

2018-01-01   100
2018-01-02   100
2018-01-03   110
2018-01-04   110
2018-01-05   111
2018-01-06   111
2018-01-07   111
2018-01-08   111
2018-01-09   101
2018-01-10   101
2018-01-11   1
2018-01-12   1

I did a lot of research using DATE_ADD, DATEDIFF, etc., also using other StackOverflow questions. But unsuccessfully. Any idea?

+4
source share
3 answers

Although I would really protect this in the application code, here is a solution that uses a small integer utility table. Instead, you can use a calendar table or build a sequence of integers on the fly ...

DROP TABLE IF EXISTS my_table;

CREATE TABLE my_table
(Perid SERIAL PRIMARY KEY
,DtFrom DATE NOT NULL
,DtTo DATE NOT NULL          
,Amount INT NOT NULL
);

INSERT INTO my_table VALUES
(1,'2018-01-01','2018-01-10',100),
(2,'2018-01-03','2018-01-08',10),
(3,'2018-01-05','2018-01-12',1);

SELECT * FROM ints;
+---+
| i |
+---+
| 0 |
| 1 |
| 2 |
| 3 |
| 4 |
| 5 |
| 6 |
| 7 |
| 8 |
| 9 |
+---+

SELECT dtfrom + INTERVAL y.i DAY dt
     , SUM(x.amount) total 
  FROM my_table x 
  JOIN ints y 
 WHERE dtfrom + INTERVAL y.i DAY <= dtto 
 GROUP 
    BY dt;
+------------+-------+
| dt         | total |
+------------+-------+
| 2018-01-01 |   100 |
| 2018-01-02 |   100 |
| 2018-01-03 |   110 |
| 2018-01-04 |   110 |
| 2018-01-05 |   111 |
| 2018-01-06 |   111 |
| 2018-01-07 |   111 |
| 2018-01-08 |   111 |
| 2018-01-09 |   101 |
| 2018-01-10 |   101 |
| 2018-01-11 |     1 |
| 2018-01-12 |     1 |
+------------+-------+

If the gap between dtfrom and dtto can be more than 10 days, you can expand the solution along these lines ...

SELECT dtfrom + INTERVAL i2.i*10 + i1.i DAY dt
     , SUM(x.amount) total
  FROM my_table x
  JOIN ints i1
  JOIN ints i2
 WHERE dtfrom + INTERVAL i2.i*10 + i1.i DAY <= dtto
 GROUP
    BY dt;
+1

select
      sum(if(STR_TO_DATE(?, '%d-%m-%Y') >= so_period_date.dt_from and 
             STR_TO_DATE(?, '%d-%m-%Y') <= so_period_date.dt_to,
          so_period_date.amount, 0)) as amount
from so_period_date
0

:

SELECT A.`DATE`, B.Amount
FROM 
(SELECT TO_DATE('2018-01-01','YYYY-MM-DD') `DATE` UNION ALL
 SELECT TO_DATE('2018-01-02','YYYY-MM-DD') `DATE` UNION ALL
 SELECT TO_DATE('2018-01-03','YYYY-MM-DD') `DATE` UNION ALL
 SELECT TO_DATE('2018-01-04','YYYY-MM-DD') `DATE` UNION ALL
 SELECT TO_DATE('2018-01-05','YYYY-MM-DD') `DATE` UNION ALL
 SELECT TO_DATE('2018-01-06','YYYY-MM-DD') `DATE` UNION ALL
 SELECT TO_DATE('2018-01-07','YYYY-MM-DD') `DATE` UNION ALL
 SELECT TO_DATE('2018-01-08','YYYY-MM-DD') `DATE` UNION ALL
 SELECT TO_DATE('2018-01-09','YYYY-MM-DD') `DATE` UNION ALL
 SELECT TO_DATE('2018-01-10','YYYY-MM-DD') `DATE` UNION ALL
 SELECT TO_DATE('2018-01-11','YYYY-MM-DD') `DATE` UNION ALL
 SELECT TO_DATE('2018-01-12','YYYY-MM-DD') `DATE`  
) A LEFT JOIN yourTable B ON A.`DATE` BETWEEN B.DtFrom AND b.DtTo;

This is a query if you have to do it in sql, but it easily gets the expected result in the application logic, as @Strawberry indicated in his comment on your question.

0
source

Source: https://habr.com/ru/post/1694525/


All Articles