SQL update multiple rows in destination table with same id but different values from other table

dba.stackexchange https://dba.stackexchange.com/questions/224170

  •  17-01-2021
  •  | 
  •  

Question

creditNote table

id      invoice_id     generated_at(timestamp)     status
10101      111          2018-02-28 14:42:39.247         generated
23982      111          2018-03-30 11:11:11.247          generated 

paymentModeAmount table

id      invoice_id     paid_on(timestamp)     payment_mode
98236      111                                 creditNote
63725      111                                 creditNote

After execution of below query OUTPUT is

paymentModeAmount table

id        invoice_id     paid_on(timestamp)       payment_mode
98236        111         2018-02-28 14:42:39.247   creditNote 
63725        111         2018-02-28 14:42:39.247   creditNote 

Here PaidOn Column has same data, but we need to get two different timestamps

Expected

id      invoice_id     paid_on(timestamp)       payment_mode
98236      111         2018-02-28 14:42:39.247   creditNote 
63725      111         2018-03-30 11:11:11.247   creditNote 

paidOn timestamp's should be different as expected

PL/SQL Function

CREATE OR REPLACE FUNCTION updatePaidOn()
RETURNS TABLE(
invoiceid BIGINT,
generatedat TIMESTAMP)
AS $$
BEGIN
RETURN QUERY SELECT
generated_invoice_id as invoiceid, generated_at as generatedat
FROM
credit_note
WHERE
status='generated';
END; $$

LANGUAGE 'plpgsql';

Execute the below function

UPDATE payment_mode_amount pm
SET paid_on = sq.generatedat
from updatePaidOn() as sq
where pm.invoice_id = sq.invoiceid
and pm.paid_on is null
and pm.payment_mode='creditNote';

Update accordingly timestamps..

Was it helpful?

Solution

If you don't care which timestamp is used for which target row, you can match the two tables by joining them on a generated "row number" using e.g. this:

with cn as (
  select id, invoice_id, generated_at, row_number() over (order by id) as rn
  from creditnote
  where status = 'generated'
), pnr as (
  select id, invoice_id, generated_at, row_number() over (order by id) as rn
  from paymentmodeamount
  where payment_mode = 'creditNote'
)
select *
from pnr 
  join cn on cn.rn = pnr.rn and cn.invoice_id = pnr.invoice_id;

This joins the rows based on the ordering of the ID values in the tables creditnote and paymentmodeamount. If you want you can also order the creditnote table by generated_at.

Given your sample data this would return something like this (this is only to demonstrate what the above join does):

id    | invoice_id | generated_at | rn | id    | invoice_id | generated_at        | rn
------+------------+--------------+----+-------+------------+---------------------+---
63725 |        111 |              |  1 | 10101 |        111 | 2018-02-28 14:42:39 |  1
98236 |        111 |              |  2 | 23982 |        111 | 2018-03-30 11:11:11 |  2

Now the above query can be used as part of an UPDATE statement to bring the rows together.

with cn as (
  select id, invoice_id, generated_at, row_number() over (order by id) as rn
  from creditnote
  where status = 'generated'
), pnr as (
  select id, invoice_id, generated_at, row_number() over (order by id) as rn
  from paymentmodeamount
  where payment_mode = 'creditNote'
)
update paymentmodeamount p
   set generated_at = cn.generated_at
from pnr 
  join cn on cn.rn = pnr.rn and cn.invoice_id = pnr.invoice_id
where p.id = pnr.id
  and p.generated_at is null;

This assumes that paymentmodeamount.id is the primary key of the table.

Note that this won't be very fast for large tables.

Online example: https://rextester.com/YXAK25669

Licensed under: CC-BY-SA with attribution
Not affiliated with dba.stackexchange
scroll top