Search code examples
postgresqljoin

PostgreSQL: extend table with additional calculated values


as result of complicated select I have the_table with the structure like:

pl_id, date, value

I also have another table (let it calls the_source) where I have a list of all vailable pl_id. The idea is to extend the_table with values from the_source which doesn't exist. The problem is that some columns must be defined exactly as expected, another - can be any (let it be 0).

CREATE TABLE the_table (
  "pl_id" INTEGER,
  "date" DATE,
  "value" INTEGER
);

INSERT INTO the_table
VALUES
  ('1', '2024-05-01', '10'),
  ('1', '2024-06-01', '11'),
  ('2', '2024-05-01', '12'),
  ('2', '2024-06-01', '13');
  

CREATE TABLE the_source (
  "pl_id" INTEGER,
  "msg" TEXT
 );
 
 INSERT INTO the_source
 VALUES
    ('1', 'aaaaa'),
    ('2', 'bbbbb'),
    ('3', 'ccccc'),
    ('4', 'ddddd');

missed records can be found by select:

select * from the_source
where not exists (
  select
    *
  from the_table
  where the_table.pl_id = the_source.pl_id)

I would like to have the_final table with folling information:

  ('1', '2024-05-01', '10'),
  ('1', '2024-06-01', '11'),
  ('2', '2024-05-01', '12'),
  ('2', '2024-06-01', '13')
  ('3', '2024-05-01', '0'),
  ('3', '2024-06-01', '0'),
  ('4', '2024-05-01', '0'),
  ('4', '2024-06-01', '0');

Is it possible realize by SQL commands?


Solution

  • Yes, that is possible, the following shows one approach. (see demo)

    with the_dates (adate) as
            (select distinct date
               from the_table
            ) 
       , msg_dates (pl_id,msg, adate) as 
           (select s.pl_id,s.msg, adate
              from the_source s
              cross join the_dates
           )
    select m.pl_id, m.adate date, coalesce(t.value,0) value 
      from msg_dates  m
      left join the_table t 
        on (t.pl_id, t.date) = (m.pl_id, m.adate) 
     order by m.pl_id, m.adate;
    

    What it does:
    First it generates a CTE the_dates which extracts each interested data from the_table. It then generate a second CTE msg_dates which combines the interested dates with each entry from the_source. Finally, the main query, joins the second CTE back to the table filling on the missing values.

    NOTE: It is generally considered poor using data types and/or reserved words as column names. Date is a Postgres data type and a SQL Standard reserved word (see documentation), Value is also a SQL Standard reserved word. For demo I changed them to t... respectively.