sqloracleoracle-apex

Oracle SQL Insert Trigger to Handle Duplicate Contacts and Update Owner Field


I have a Oracle SQL table named CONTACTS with the columns ID, NAME, PHONE, OWNER. ID is Primary Key, Phone and (Name, Phone) are unique.

I have a insert query for this table :

BEGIN
    INSERT INTO CONTACTS (NAME, PHONE, OWNER)
    VALUES (:P170_NAME, :P170_PHONE, :APP_USER);
END;

And in front-end, I am trying to create a trigger for those situations below:

  1. When someone tries to create a new contact with a new phone, it can be created, all is fine
  2. When someone tries to create a new contact that is already created by another user which is also unique due to (name, phone), update the owner column of that phone number and store both owners separating with comma, here is an example:

If ('Mustafa Turhan', '905554443322', 'M.TURHAN') is already created and someone tries to create ('Mustafa Turhan', '905554443322', 'K.AKKUS'), it should do this: ('1','Mustafa Turhan', '905554443322', 'M.TURHAN,K.AKKUS')

  1. When someone tries to create ('Alihan Turhan', '905554443322', 'K.CEKIC') it should throw an error because 'phone' is unique.

Solution

  • If you can have mutliple OWNERs then store the values in a separate table. Do NOT store muliple values in a comma-delimited string.

    CREATE SEQUENCE contacts__id__seq;
    CREATE SEQUENCE contact_owners__id__seq;
    
    CREATE TABLE contacts (
      id    NUMBER
            DEFAULT contacts__id__seq.NEXTVAL
            CONSTRAINT contacts__id__pk PRIMARY KEY,
      name  VARCHAR2(50)
            NOT NULL,
      phone VARCHAR2(20)
            CONSTRAINT contacts__phone__u UNIQUE
    );
    
    CREATE TABLE contact_owners (
      id         NUMBER
                 DEFAULT contact_owners__id__seq.NEXTVAL
                 CONSTRAINT contact_owners__id__pk PRIMARY KEY,
      contact_id NOT NULL
                 CONSTRAINT contact_owners__cid__fk REFERENCES contacts(id),
      owner      VARCHAR2(20)
                 NOT NULL,
      CONSTRAINT contact_owners__cid__o__u UNIQUE (contact_id, owner)
    );
    

    Then when you want to insert a value you can use:

    DECLARE
      v_id    CONTACTS.ID%TYPE;
    BEGIN
      BEGIN
        INSERT INTO contacts (id, name, phone)
        VALUES (DEFAULT, :P170_NAME, :P170_PHONE)
        RETURNING id INTO v_id;
      EXCEPTION
        WHEN DUP_VAL_ON_INDEX THEN
          BEGIN
            SELECT id
            INTO   v_id
            FROM   contacts
            WHERE  phone = :P170_PHONE
            AND    name  = :P170_NAME;
    
            GOTO skip_raise_error;
          EXCEPTION
            WHEN NO_DATA_FOUND THEN
              NULL;
              -- Fall through and raise the previous error.
          END;
          RAISE;
      END;
    
      <<skip_raise_error>>
      MERGE INTO contact_owners dst
      USING DUAL
      ON (v_id = dst.contact_id AND :APP_USER = dst.owner)
      WHEN NOT MATCHED THEN
        INSERT (id, contact_id, owner) VALUES (DEFAULT, v_id, :APP_USER);
    END;
    /
    

    fiddle