'Update column in table A based off columns in table B which have to meet a condition

Hi I have 2 tables to model a vacation request and the approvers who will approve the request. A request can have several approvers.

When an approver approves, the approver row has its approved_at column set to the current date.

The request table also has an approved_at column. This is set when ALL the approvers have approved and it is set to the most recent approver's approved_at date.

I need to backfill the requests table's approved at column with the most recent approver's approved_at time but only if all the approvers have approved.

I have solved it using a CTE with window functions but I'm wondering what other ways are there to solve this? I'd prefer a solution compliant with postgres.

Here's my solution

create table reqs (
  id serial primary key,
  approved_at date
);

create table req_approvers (
  id serial primary key,
  req_id int,
  approved_at date
);

insert into reqs (id) values (1),(2),(3);

insert into req_approvers (req_id, approved_at)
values
(1, '2022-01-01'),
(1, '2021-01-01'),
(1, NULL),
(1, '2020-01-01'),
(2, '1999-01-01'),
(2, '1979-01-01');

-- View the data by joining the two tables on the req_id 

select 
reqs.id as req_id, 
reqs.approved_at as req_approved_at, 
req_approvers.id as req_apvr_id,
req_approvers.req_id as req_apvr_req_id,
req_approvers.approved_at as req_apvr_approved_at
from reqs
left outer join req_approvers on req_approvers.req_id = reqs.id;


/*
 req_id | req_approved_at | req_apvr_id | req_apvr_req_id | req_apvr_approved_at
--------+-----------------+-------------+-----------------+----------------------
      1 |                 |           1 |               1 | 2022-01-01
      1 |                 |           2 |               1 | 2021-01-01
      1 |                 |           3 |               1 |
      1 |                 |           4 |               1 | 2020-01-01
      2 |                 |           5 |               2 | 1999-01-01
      2 |                 |           6 |               2 | 1979-01-01
      3 |                 |             |                 |
*/

-- From the above only req 2 has been fully approved so only its approved_at column should be set to the date 1999-01-01


WITH req_approval_stats AS (
    SELECT
            DISTINCT reqs.id
            -- get the most recent approvers approval date
            ,MAX (req_approvers.approved_at) OVER (
                PARTITION BY reqs.id
            ) AS approved_at
            -- get the total number of approvers for this request
            ,COUNT (req_approvers.id) OVER (
                PARTITION BY reqs.id
            ) AS total_approvers
            -- get the total number of approvers who have approved for this request
            ,COUNT (req_approvers.approved_at) OVER (
                PARTITION BY reqs.id
            ) AS total_approved
        FROM
            reqs INNER JOIN req_approvers
                ON reqs.id = req_approvers.req_id
) UPDATE
        reqs
    SET
        approved_at = (
            SELECT
                    req_approval_stats.approved_at
                FROM
                    req_approval_stats
                WHERE
                    req_approval_stats.total_approvers = req_approval_stats.total_approved
                    AND req_approval_stats.id = reqs.id LIMIT 1
        )


-- view the data again and its correct 
 
/*
 req_id | req_approved_at | req_apvr_id | req_apvr_req_id | req_apvr_approved_at
--------+-----------------+-------------+-----------------+----------------------
      1 |                 |           1 |               1 | 2022-01-01
      1 |                 |           2 |               1 | 2021-01-01
      1 |                 |           3 |               1 |
      1 |                 |           4 |               1 | 2020-01-01
      2 | 1999-01-01      |           5 |               2 | 1999-01-01
      2 | 1999-01-01      |           6 |               2 | 1979-01-01
      3 |                 |             |                 |
*/



Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source