K
K
KTG2019-01-24 13:27:03
Oracle
KTG, 2019-01-24 13:27:03

How to fill empty rows with previous value (lag + left join)?

I want to display the weighted average cost of the client's balances, for a month which falls on 1 day.
I form a temporary table with dates for the period:

WITH
    DAYS# AS
        (
            SELECT
                  LSTDATE
                FROM
                    (
                        SELECT 
                          :pBegDate + LEVEL - 1 AS LSTDATE
                        FROM dual 
                        START WITH :pBegDate <= :pEndDate
                        CONNECT BY :pBegDate + LEVEL - 1 <= :pEndDate
                    ) 
        )

Further we have a plate "CUSTOMER" with one field - ID
ID
---
101
and we do CROSS JOIN of tables.
We get the output of the client number for each date.
We have BAL residual tables. which captures only changes in the balance, there are 3 fields:
ID - DATE - SUM
---------------------
101 - 11/30/2017 - 50
101 - 01/02/2018 - 300
101 - 01/05/2018 - 500
101 - 01/07/2018 - 700
For example, select the period: 01/01/2018 - 01/07/2018.
As a result, I want to get in the final sample:
101 - 01/01/2018 - 50 - the amount is taken for 11/30/2017, because this will be the last balance at the beginning of the period. If it was not, then 0.
101 - 01/02/2018 - 300
101 - 01/03/2018 - 300 - amount taken for 01/02
101 - 01/04/2018 - 300 - amount taken for 01/02
101 - 01/05/2018 - 500
101 - 01/06/2018 - 500 - amount taken for 01/05/101
- 07/07
When I connect it via LEFT JOIN, of course, I do not see the amount for the days on which no purchases were made. LAG does not react to the missing record in any way, and we cannot determine how "distant" the previous record should be looked at.
So now it goes like this:
101 - 01/01/2018 -
101 - 01/02/2018 - 300
101 - 01/03/2018 -
101 - 01/04/2018 -
101 - 01/05/2018 - 500
101 - 01/06/2018 -
101 - 01.07 - 01.01 700

Answer the question

In order to leave comments, you need to log in

2 answer(s)
M
Maxim Y, 2019-01-28
@x_shader

A blank without inline subqueries looks like the code below. There is only one query to the table with data.
But it is necessary to refine it with a file in order to cling to the first account balance that was not included in the reporting period.
(e.g., with a union, paste one line into the lowest subquery)

WITH dt_range AS (
  SELECT TRUNC (&dt_start + ROWNUM - 1) dt
    FROM DUAL CONNECT BY ROWNUM <= &dt_end - &dt_start + 1
)
,bal AS (
  SELECT 101 id_, to_date('20171130', 'yyyymmdd') date_, 50 sum_ FROM DUAL UNION ALL
  SELECT 101, to_date('20180102', 'yyyymmdd'), 300 FROM DUAL UNION ALL
  SELECT 101, to_date('20180105', 'yyyymmdd'), 500 FROM DUAL UNION ALL
  SELECT 101, to_date('20180107', 'yyyymmdd'), 700 FROM DUAL 
)


SELECT id_ --MAX(id_) OVER (PARTITION BY grp) id_
      ,dt
      ,MAX(sum_) OVER (PARTITION BY grp) sum_
  FROM (
        SELECT t1.*
              ,SUM(start_of_group) OVER(ORDER BY t1.dt) grp
           FROM (
                  SELECT bal.id_
                        ,dt_range.dt
                        ,bal.sum_
                        ,CASE WHEN bal.sum_ IS NOT NULL THEN 1 END start_of_group
                  FROM dt_range
                  LEFT JOIN bal ON dt_range.dt = bal.date_
                ) t1
        )
   ORDER BY dt

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question