Retrieving identity of most recent insert in Oracle DB 12c

Question:

I’d like to have returned to me (via cx_oracle in python) the value of the Identity that’s created for a row that I’m inserting. I think I can figure out the python bit on my own, if someone could please state how to modify my SQL statement to get the ID of the newly-created row.

I have a table that’s created with something like the following:

CREATE TABLE hypervisor
  (
    id NUMBER GENERATED BY DEFAULT AS IDENTITY (
    START WITH 1 NOCACHE ORDER ) NOT NULL ,
    name       VARCHAR2 (50)
  )
  LOGGING ;
ALTER TABLE hypervisor ADD CONSTRAINT hypervisor_PK PRIMARY KEY ( id ) ;

And I have SQL that’s similar to the following:

insert into hypervisor ( name ) values ('my hypervisor')

Is there an easy way to obtain the id of the newly inserted row? I’m happy to modify my SQL statement to have it returned, if that’s possible.

Most of the google hits on this issue were for version 11 and below, which don’t support automatically-generated identity columns so hopefully someone here can help out.

Asked By: interestedparty333

||

Answers:

Use the returning clause of the insert statement.

insert into hypervisor (name ) values ('my hypervisor')
 returning id into :python_var

You said you could handle the Python bit ? You should be able to “bind” the return parameter in your program.

Answered By: Marco Polo

Taking what user2502422 said above and adding the python bit:

newest_id_wrapper = cursor.var(cx_Oracle.STRING)
sql_params = { "newest_id_sql_param" : newest_id_wrapper }
sql = "insert into hypervisor ( name ) values ('my hypervisor') " +              
      "returning id into :python_var"
cursor.execute(sql, sql_params)
newest_id=newest_id_wrapper.getvalue()
Answered By: interestedparty333

This example taken from learncodeshare.net has helped me grasp the correct syntax.

cur = con.cursor()

new_id = cur.var(cx_Oracle.NUMBER)

statement = 'insert into cx_people(name, age, notes) values (:1, :2, :3) returning id into :4'
cur.execute(statement, ('Sandy', 31, 'I like horses', new_id))

sandy_id = new_id.getvalue()

pet_statement = 'insert into cx_pets (name, owner, type) values (:1, :2, :3)'
cur.execute(pet_statement, ('Big Red', sandy_id, 'horse'))

con.commit()

It’s only slightly different from ragerdl’s answer, but different enough to be added here I believe!
Notice the absence of sql_params = { "newest_id_sql_param" : newest_id_wrapper }

Answered By: Félix Paradis

I liked the answer by Marco Polo, but it is incomplete.
The answer from FelDev is good too but does not address named parameters.
Here is a more complete example from code I wrote with a simplified table (less fields). I have omitted code on how to set up a cursor since that is well documented elsewhere.

import cx_Oracle

INSERT_A_LOG = '''INSERT INTO A_LOG(A_KEY, REGION, DIR_NAME, FILENAME)
VALUES(A_KEY_Sequence.nextval, :REGION, :DIR_NAME, :FILENAME)
RETURNING A_KEY INTO :A_LOG_ID'''

CURSOR = None

class DataProcessor(Process):
    # Other code for setting up connection to DB and storing it in CURSOR
    def save_log_entry(self, row):
        global CURSOR
        # Oracle variable to hold value of last insert
        log_var = CURSOR.var(cx_Oracle.NUMBER)
        row['A_LOG_ID'] = log_var

        row['REGION'] = 'R7' # Other entries set elsewhere
        try:
            # This will fail unless row.keys() = 
            # ['REGION', 'DIR_NAME', 'FILE_NAME', 'A_LOG_ID']
            CURSOR.execute(INSERT_A_LOG, row)
        except Exception as e:
            row['REJCTN_CD'] = 'InsertFailed'
            raise

        # Get last inserted ID from Oracle for update
        self.last_log_id = log_var.getvalue()
        print('Insert id was {}'.format(self.last_log_id))
Answered By: Bradley Slavik

Agreeing with the older answers. However, depending on your version of cx_Oracle (7.0 and newer), var.getvalue() might return an array instead of a scalar.
This is to support multiple return values as stated in this comment.

Also note, that cx_Oracle is deprecated and has moved to oracledb now.

Example:

newId = cur.var(oracledb.NUMBER, outconverter=int)
sql = """insert into Locations(latitude, longitude) values (:latitude, :longitude) returning locationId into :newId"""
sqlParam = [latitude, longitude, newId]
cur.execute(sql, sqlParam)
newIdValue = newId.getvalue()

newIdValue would return [1] instead of 1

Answered By: luxorbis
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.