For this kind of thing, I like to keep a separate table of what I think the remote database looks like.  That way, I can:
- Generate deltas easily by comparing my source data with my copy of what should be in the remote database.
- Correct errors in PROD by updating the copy to force the process to resend (e.g., if the team managing the other database misses a file or something).
Here is a working example to illustrate the process.
Cast of characters:
- SO_SERVICES--> your source table
- SO_SERVICES_EXPORTED--> a copy of what the remote database should currently look like, if they've processed all our command .csv files correctly.
- SO_SERVICES_EXPORT_CMDS--> the set of deltas generated by comparing- SO_SERVICESand- SO_SERVICES_EXPORTED. You would generate your .csv file from this table and then delete from it.
- SYNC_SERVICES--> a procedure to generate the deltas
Setup Tables
CREATE TABLE so_services
 ( service_id            NUMBER NOT NULL,
   id_service_provider   NUMBER NOT NULL,
   valid_from            DATE NOT NULL,
   valid_to              DATE DEFAULT DATE '9999-12-31' NOT NULL,
   CONSTRAINT so_services_pk PRIMARY KEY ( service_id, id_service_provider ),
   CONSTRAINT so_services_c1 CHECK ( valid_from <= valid_to ) );
CREATE TABLE so_services_exported
 ( service_id            NUMBER NOT NULL,
   id_service_provider   NUMBER NOT NULL,
   valid_from            DATE NOT NULL,
   valid_to              DATE DEFAULT DATE '9999-12-31' NOT NULL,
   CONSTRAINT so_services_exported_pk PRIMARY KEY ( service_id ),
   CONSTRAINT so_services_exported_c1 CHECK ( valid_from <= valid_to ) );
CREATE TABLE so_services_export_cmds
 ( service_id            NUMBER NOT NULL,
   id_service_provider   NUMBER,
   cmd                   VARCHAR2(30) NOT NULL,
   valid_from            DATE,
   valid_to              DATE,
   CONSTRAINT so_services_export_cmds_pk PRIMARY KEY ( service_id, cmd ) );
Procedure to process synchronization
-- You would put this in a package, for real code
CREATE OR REPLACE PROCEDURE sync_services IS
BEGIN
  LOCK TABLE so_services IN EXCLUSIVE MODE; 
  -- Note the deltas between the current active services and what we've exported so far
  -- CAVEAT: I am not sweating your exact business logic here.  I am just trying to illustrate the approach.
  -- The logic here assumes that the target database wants only one row for each service_id, so we will send an
  -- "ADD" if the target database should insert a new service ID, "UPDATE", if it should modify an existing service ID,
  -- or "DELETE" if it should delete it.
  -- Also assuming, for "DELETE" command, we only need the service_id, no other fields.
  INSERT INTO so_services_export_cmds
     ( service_id, id_service_provider, cmd, valid_from, valid_to )
  SELECT nvl(so.service_id, soe.service_id) service_id,
         so.id_service_provider id_service_provider,
         CASE WHEN so.service_id IS NOT NULL AND soe.service_id IS NULL THEN 'ADD'
              WHEN so.service_id IS NULL AND soe.service_id IS NOT NULL THEN 'DELETE'
              WHEN so.service_id IS NOT NULL AND soe.service_id IS NOT NULL THEN 'UPDATE'
              ELSE NULL -- this will fail and should.
         END cmd,
         so.valid_from valid_from,
         so.valid_to valid_to
  FROM  ( SELECT * FROM so_services WHERE SYSDATE BETWEEN valid_from AND valid_to ) so
  FULL OUTER JOIN so_services_exported soe ON soe.service_id = so.service_id
  -- Exclude any UPDATES that don't change anything
  WHERE   NOT (     soe.service_id IS NOT NULL 
            AND so.service_id IS NOT NULL 
            AND so.id_service_provider = soe.id_service_provider 
            AND so.valid_from = soe.valid_from 
            AND so.valid_to = soe.valid_to);
  -- Update the snapshot of what the remote database should now look like after processing the above commands.
  -- (i.e., it should have all the current records from the service table)
  DELETE FROM so_services_exported;
  INSERT INTO so_services_exported
     ( service_id, id_service_provider, valid_from, valid_to )
  SELECT service_id, id_service_provider, valid_from, valid_to 
  FROM   so_services so
  WHERE  SYSDATE BETWEEN so.valid_from AND so.valid_to;
  -- For testing (12c only)
  DECLARE
    c SYS_REFCURSOR;
  BEGIN
    OPEN c FOR SELECT * FROM so_services_export_cmds ORDER BY service_id;
    DBMS_SQL.RETURN_RESULT(c);
  END;
  COMMIT;  -- Release exclusive lock on services table
END sync_services;
Insert Test Data from OP
DELETE FROM so_services;
INSERT INTO so_services ( service_id, id_service_provider, valid_from, valid_to )
VALUES ( 114, 20, DATE '2011-12-06', DATE '2017-10-16' );
INSERT INTO so_services ( service_id, id_service_provider, valid_from, valid_to )
VALUES ( 211, 65, DATE '2015-05-09', DATE '9999-12-31' );
INSERT INTO so_services ( service_id, id_service_provider, valid_from, valid_to )
VALUES ( 322, 57, DATE '2019-08-22', DATE '9999-12-31' );
INSERT INTO so_services ( service_id, id_service_provider, valid_from, valid_to )
VALUES ( 336, 21, DATE '2009-08-20', DATE '2019-07-11' );
INSERT INTO so_services ( service_id, id_service_provider, valid_from, valid_to )
VALUES ( 336, 37, DATE '2019-07-11', DATE '9999-12-31' );
Test #1 -- Nothing exported yet, so all latest records should be sent
exec sync_services;
SERVICE_ID ID_SERVICE_PROVIDER CMD                            VALID_FRO VALID_TO 
---------- ------------------- ------------------------------ --------- ---------
       211                  65 ADD                            09-MAY-15 31-DEC-99
       322                  57 ADD                            22-AUG-19 31-DEC-99
       336                  37 ADD                            11-JUL-19 31-DEC-99
Test #2 -- no additional updates, no additional commands
DELETE FROM so_services_export_cmds;  -- You would do this after generating your .csv file
exec sync_services;
no rows selected
Test #3 - Add some changes to the source table
-- Add a new service #400
INSERT INTO so_services ( service_id, id_service_provider, valid_from, valid_to )
VALUES ( 400, 20, DATE '2019-08-29', DATE '9999-12-31' );
-- Terminate service 322
UPDATE so_services 
SET    valid_to = DATE '2019-08-29'
WHERE  service_id = 322
AND    valid_to = DATE '9999-12-31';
-- Update service 336
UPDATE so_services 
SET    valid_to = DATE '2019-08-29'
WHERE  service_id = 336
AND    id_service_provider = 37
AND    valid_to = DATE '9999-12-31';
INSERT INTO so_services ( service_id, id_service_provider, valid_from, valid_to )
VALUES ( 336, 88, DATE '2019-08-29', DATE '9999-12-31' );
exec sync_services;
SERVICE_ID ID_SERVICE_PROVIDER CMD                            VALID_FRO VALID_TO 
---------- ------------------- ------------------------------ --------- ---------
       322                     DELETE                                            
       336                  88 UPDATE                         29-AUG-19 31-DEC-99
       400                  20 ADD                            29-AUG-19 31-DEC-99