Skip to Main Content
  • Questions
  • Copy row value down until next non-null row

Breadcrumb

Question and Answer

Chris Saxon

Thanks for the question, Jay.

Asked: November 06, 2019 - 4:29 pm UTC

Last updated: November 07, 2019 - 2:39 pm UTC

Version: 11g

Viewed 1000+ times

You Asked

Hi,

Is there a simple way to achieve the following output in SQL?

Wanted to populate the null values with the Country name until there is a new country name.

Thanks

with data as
(
select 'Afghanistan Afghani' as country_currency, NULL as amount, 'Afghanistan' country from dual union all
select 'Kabul' as country_currency, '200' as amount, NULL country from dual union all
select 'Elsewhere' as country_currency, '100' as amount, NULL country from dual union all
select 'Albania (Albania Lek(e))' as country_currency, null as amount, 'Albania' country from dual union all
select 'Tirana' as country_currency, '100' as amount, NULL country from dual union all
select 'Shkodra' as country_currency, '200' as amount, NULL country from dual union all
select 'Vlore' as country_currency, '200' as amount, NULL country from dual union all
select 'Elsewhere' as country_currency, '200' as amount, NULL country from dual union all
select 'Algeria (Algerian Dinar)' as country_currency, null as amount, 'Algeria' country from dual union all
select 'Algiers' as country_currency, '100' as amount, NULL country from dual union all
select 'Adrar' as country_currency, '200' as amount, NULL country from dual union all
select 'Oran' as country_currency, '200' as amount, NULL country from dual union all
select 'Elsewhere' as country_currency, '200' as amount, NULL country from dual
)
select
*
from
data

and Connor said...

Thanks for the test data. We need something which *defines* the order, so I've added a sequence number. After that, its easy with a bit of LAG

SQL> with data as
  2  (
  3  select 1 x, 'Afghanistan Afghani' as country_currency, NULL as amount, 'Afghanistan' country from dual union all
  4  select 2,'Kabul' as country_currency, '200' as amount, NULL country from dual union all
  5  select 3,'Elsewhere' as country_currency, '100' as amount, NULL country from dual union all
  6  select 4,'Albania (Albania Lek(e))' as country_currency, null as amount, 'Albania' country from dual union all
  7  select 5,'Tirana' as country_currency, '100' as amount, NULL country from dual union all
  8  select 6,'Shkodra' as country_currency, '200' as amount, NULL country from dual union all
  9  select 7,'Vlore' as country_currency, '200' as amount, NULL country from dual union all
 10  select 8,'Elsewhere' as country_currency, '200' as amount, NULL country from dual union all
 11  select 9,'Algeria (Algerian Dinar)' as country_currency, null as amount, 'Algeria' country from dual union all
 12  select 10,'Algiers' as country_currency, '100' as amount, NULL country from dual union all
 13  select 11,'Adrar' as country_currency, '200' as amount, NULL country from dual union all
 14  select 12,'Oran' as country_currency, '200' as amount, NULL country from dual union all
 15  select 13,'Elsewhere' as country_currency, '200' as amount, NULL country from dual
 16  )
 17  select d.*,
 18         nvl(country, lag(country ignore nulls) over ( order by x ) ) as filler
 19  from data d
 20  order by x;

         X COUNTRY_CURRENCY         AMO COUNTRY     FILLER
---------- ------------------------ --- ----------- -----------
         1 Afghanistan Afghani          Afghanistan Afghanistan
         2 Kabul                    200             Afghanistan
         3 Elsewhere                100             Afghanistan
         4 Albania (Albania Lek(e))     Albania     Albania
         5 Tirana                   100             Albania
         6 Shkodra                  200             Albania
         7 Vlore                    200             Albania
         8 Elsewhere                200             Albania
         9 Algeria (Algerian Dinar)     Algeria     Algeria
        10 Algiers                  100             Algeria
        11 Adrar                    200             Algeria
        12 Oran                     200             Algeria
        13 Elsewhere                200             Algeria

13 rows selected.


Rating

  (2 ratings)

Is this answer out of date? If it is, please let us know via a Comment

Comments

Version?

Stew Ashton, November 07, 2019 - 8:24 am UTC

I didn't know LAG/LEAD had the IGNORE NULLS option, thanks!

However, it looks like that option was added in version 11.2. Does the OP have that version?

If not, perhaps LAST_VALUE would be an alternative solution?

Best regards,
Stew
Chris Saxon
November 07, 2019 - 2:39 pm UTC

Well all they say is 11g... so I hope they're on 11.2!

But yes, LAST_VALUE will also work.

Using LAST_VALUE

Jay Vanamoju, November 07, 2019 - 9:00 am UTC

Hi,

Thanks for your response. It was very useful.
Do you see any disadvantages of using the below approach?

with data as
(
select 1 x, 'Afghanistan Afghani' as country_currency, NULL as amount, 'Afghanistan' country from dual union all
select 2,'Kabul' as country_currency, '200' as amount, NULL country from dual union all
select 3,'Elsewhere' as country_currency, '100' as amount, NULL country from dual union all
select 4,'Albania (Albania Lek(e))' as country_currency, null as amount, 'Albania' country from dual union all
select 5,'Tirana' as country_currency, '100' as amount, NULL country from dual union all
select 6,'Shkodra' as country_currency, '200' as amount, NULL country from dual union all
select 7,'Vlore' as country_currency, '200' as amount, NULL country from dual union all
select 8,'Elsewhere' as country_currency, '200' as amount, NULL country from dual union all
select 9,'Algeria (Algerian Dinar)' as country_currency, null as amount, 'Algeria' country from dual union all
select 10,'Algiers' as country_currency, '100' as amount, NULL country from dual union all
select 11,'Adrar' as country_currency, '200' as amount, NULL country from dual union all
select 12,'Oran' as country_currency, '200' as amount, NULL country from dual union all
select 13,'Elsewhere' as country_currency, '200' as amount, NULL country from dual
)
/*select d.*,
nvl(country, lag(country ignore nulls) over ( order by x ) ) as filler
from data d
order by x;*/
SELECT country_currency,
last_value( country ignore nulls )
OVER (order by X
rows between unbounded preceding and current row
) as new_temp
from data d

Thanks
Chris Saxon
November 07, 2019 - 2:39 pm UTC

Nope, last_value will work fine too.

More to Explore

Analytics

Analytic SQL got you confused? Check out Connor McDonald's complete video course.