Search code examples
python-3.xpostgresqlcalendarconditional-statementsseries

Is it possible to generate columns based on input columns in PostgreSQL


I have a table like this in PostgreSQL with 3 initial columns called Project, Size, and StartDate (see below):

Project Size StartDate
Project1 88 2020-06-15
Project2 105 2020-03-01

I need to add 12 columns next to StartDate column and extend the initial table to 15 columns. All new columns represent months for given year (2020), and they will contain 0 and values calculated based on conditional logic derived from Size and StartDate columns. The condition is the following: if the StartDate belongs to a specific month, that month gets a value=Size and after that for each next month the Value=Value-50 until Value >0. Please check the expected outcome below:

Project Size StartDate Jan Feb Mar Apr Mai Jun Jul Aug Sep Oct Nov Dec
Project1 88 2020-06-15 0 0 0 0 88 38 0 0 0 0 0 0
Project2 105 2020-03-01 0 0 105 55 5 0 0 0 0 0 0 0

Solution

  • This can be done with a lot of CASE expressions:

    SELECT project,
           size,
           startdate,
           CASE WHEN mon < 2
                THEN greatest(size - 50 * (1 - mon), 0)
                ELSE 0
           END AS jan,
           CASE WHEN mon < 3
                THEN greatest(size - 50 * (2 - mon), 0)
                ELSE 0
           END AS feb,
           CASE WHEN mon < 4
                THEN greatest(size - 50 * (3 - mon), 0)
                ELSE 0
           END AS mar,
           CASE WHEN mon < 5
                THEN greatest(size - 50 * (4 - mon), 0)
                ELSE 0
           END AS apr,
           CASE WHEN mon < 6
                THEN greatest(size - 50 * (5 - mon), 0)
                ELSE 0
           END AS may,
           CASE WHEN mon < 7
                THEN greatest(size - 50 * (6 - mon), 0)
                ELSE 0
           END AS jun,
           CASE WHEN mon < 8
                THEN greatest(size - 50 * (7 - mon), 0)
                ELSE 0
           END AS jul,
           CASE WHEN mon < 9
                THEN greatest(size - 50 * (8 - mon), 0)
                ELSE 0
           END AS aug,
           CASE WHEN mon < 10
                THEN greatest(size - 50 * (9 - mon), 0)
                ELSE 0
           END AS sep,
           CASE WHEN mon < 11
                THEN greatest(size - 50 * (10 - mon), 0)
                ELSE 0
           END AS oct,
           CASE WHEN mon < 12
                THEN greatest(size - 50 * (11 - mon), 0)
                ELSE 0
           END AS nov,
           CASE WHEN mon < 13
                THEN greatest(size - 50 * (12 - mon), 0)
                ELSE 0
           END AS dec
    FROM (SELECT project,
                 size,
                 startdate,
                 extract(month FROM startdate) AS mon
          FROM mytable) AS q;