Home > Software design >  Get all numbers 1-100 per ID even without data
Get all numbers 1-100 per ID even without data

Time:04-30

I have a table which looks like this:

ID money_earned days_since_start
1 1000 1
1 2000 2
1 3000 4
1 2000 5
2 1000 1
2 100 3

I want that rows, without a days_since_start (which means that the money_earned column was empty that day) - will include all the days PER ID, with "money" being null to indicate there was no earnings, so it to look like this:

ID money_earned days_since_start
1 1000 1
1 2000 2
1 NULL 3
1 3000 4
1 2000 5
2 1000 1
1 NULL 2
2 100 3

I have tried to look up for something like that, but I don't even know what function does that...

thank you!

CodePudding user response:

You can first generate table for your ids and days by query

SELECT d1.id, generate_series(1, max(d1.days_since_start)) AS days_since_start
FROM days d1 JOIN days d2 ON d1.id = d2.id GROUP BY d1.id

(if you need all numbers from 1 to 100, you can replase exspression max(d1.days_since_start) with the number 100)

and then join it with your table. the final query might look like this

WITH genDays AS
     (SELECT d1.id, generate_series(1, max(d1.days_since_start)) AS days_since_start
      FROM days d1 JOIN days d2 ON d1.id = d2.id GROUP BY d1.id)

SELECT coalesce(genDays.id, d3.id) AS id,
       d3.money_earned,
       coalesce(d3.days_since_start, genDays.days_since_start) AS days_since_start
FROM days d3 FULL JOIN genDays ON genDays.id = d3.id
                     AND genDays.days_since_start = d3.days_since_start

the output will be as you need

if you need to fill the nulls with last nonnull value per id then you can modify the query like here

WITH genDays AS
     (SELECT d1.id as id, generate_series(1,  100) AS days_since_start
      FROM days d1 JOIN days d2 ON d1.id = d2.id GROUP BY d1.id)

SELECT coalesce(genDays.id, d3.id) AS id,
       coalesce(d3.money_earned, 
            (
                select d4.money_earned
                from days d4
                where d4.id = genDays.id
                  and d4.days_since_start < genDays.days_since_start
                order by d4.days_since_start desc
                limit 1
            )) as money_earned,
       coalesce(d3.days_since_start, genDays.days_since_start) AS days_since_start
FROM days d3 FULL JOIN genDays ON genDays.id = d3.id
                  AND genDays.days_since_start = d3.days_since_start
  • Related