Search code examples
postgresqldatabase-migrationpostgresql-9.5

Merge in postgres


Am trying to convert below oracle query to postgres,

MERGE INTO table1 g
USING (SELECT distinct g.CDD , d.SGR
from  table2 g, table3 d
where g.IDF = d.IDF) f
ON (g.SGR = f.SGR and g.CDD = f.CDD)
   WHEN NOT MATCHED THEN
   INSERT (SGR, CDD)
   VALUES (f.SGR, f.CDD);

I made changes as below compatible to postgres:

WITH f AS (
SELECT distinct g.CDD , d.SGR
from  table2 g, table3 d
where g.IDF = d.IDF
),
upd AS (
update table1 g 
set 
SGR = f.SGR , CDD = f.CDD 
FROM f where g.SGR = f.SGR  and g.CDD = f.CDD  
returning g.CDD, g.SGR
)
INSERT INTO table1(SGR, CDD ) SELECT f.SGR, f.CDD FROM f;

But am doubtful ,my oracle query is not updating any columns if data matched , but am unable to convert it accordingly . Can anyone help me to correct it ?


Solution

  • Assuming you have a primary (or unique) key on (sgr, cdd) you can convert this to an insert ... on conflict statement:

    insert into table1 (SGR, CDD)
    select  distinct g.CDD, d.SGR
    from table2 g
      join table3 d ON g.IDF = d.IDF
    on conflict (cdd, sgr) do nothing;
    

    If you don't have a unique constraint (which bears the question: why?) then a straight-forward INSERT ... SELECT statement should work (which would have worke in Oracle as well).

    WITH f AS (
       SELECT distinct g.CDD, d.SGR
       from table2 g
         join table3 d on g.IDF = d.IDF
    )
    INSERT INTO table1 (SGR, CDD) 
    SELECT f.SGR, f.CDD 
    FROM f
    WHERE NOT EXISTS (select *
                      from table1 t1
                         join f on (t1.sgr, t1.cdd) = (f.cdd, f.sgrf));
    

    Note that this is NOT safe for concurrent execution (and neither is Oracle's MERGE statement). You can still wind up with duplicate values in table1 (with regards to the combination of (sgr,cdd)).

    The only sensible way to prevent duplicates is to create a unique index (or constraint) - which would enable you to use the much more efficient insert on conflict. You should really consider that if your business rules disallow duplicates.


    Note that I converted your ancient, implicit join in the WHERE clause to a modern, explicit JOIN operator, but it is not required for this to work.