Search code examples
firebird

How to INSERT OR UPDATE while MATCHING a non Primary Key without updating existing Primary Key?


I'm currently working with Firebird and attempting to utilize UPDATE OR INSERT functionality in order to solve a particular new case within our software. Basically, we are needing to pull data off of a source and put it into an existing table and then update that data at regular intervals and adding any new references. The source is not a database so it isn't a matter of using MERGE to link the two tables (unless we make a separate table and then merge it, but that seems unnecessary).

The problem rests on the fact we cannot use the primary key of the existing table for matching, because we need to match based off of the ID we get from the source. We can use the MATCHING clause no problem but the issue becomes that the primary key of the existing table will be updated to the next key every time because it has to be in the query because of the insertion chance. Here is the query (along with c# parameter additions) to demonstrate the problem.

UPDATE OR INSERT INTO existingtable (PrimaryKey, UniqueSourceID, Data) VALUES (?,?,?) MATCHING (UniqueSourceID);

this.AddInParameter("PrimaryKey", FbDbType.Integer, itemID);

this.AddInParameter("UniqueSourceID", FbDbType.Integer, source.id);

this.AddInParameter("Data", FbDbType.SmallInt, source.data);

Problem is shown that every time the UPDATE triggers, the primary key will also change to the next incremented key I need a way to leave the primary key alone when updating, but if it is inserting I need to insert it.


Solution

  • Do not generate primary key manually, let a trigger generate it when nessesary:

    CREATE SEQUENCE seq_existingtable;
    
    SET TERM ^ ;
    
    CREATE TRIGGER Gen_PK FOR existingtable
    ACTIVE BEFORE INSERT
    AS
    BEGIN
      IF(NEW.PrimaryKey IS NULL)THEN NEW.PrimaryKey = NEXT VALUE FOR seq_existingtable;
    END^
    
    SET TERM ; ^
    

    Now you can omit the PK field from your statement:

    UPDATE OR INSERT INTO existingtable (UniqueSourceID, Data) VALUES (?,?) MATCHING (UniqueSourceID);
    

    and when the insert is triggered by the statement then the trigger will take care of creating the PK. If you need to know the generated PK then use the RETURNING clause of the UPDATE OR INSERT statement.