tags:

views:

1180

answers:

3

Hi,

I know that in Oracle I can get the generated id (or any other column) from an inserted row as an output parameter. Ex:

insert into foo values('foo','bar') returning id into :myOutputParameter

Is there a way to do the same, but using ExecuteScalar instead of ExecuteNonQuery?

I don't want to use output parameters or stored procedures.

ps: I'm using Oracle, not sql server!!!

A: 

If you are on oracle, you have to use ExecuteNonQuery and ResultParameter. There is no way to write this as query.

using (OracleCommand cmd = con.CreateCommand()) {
    cmd.CommandText = "insert into foo values('foo','bar') returning id into :myOutputParameter";
    cmd.Parameters.Add(new OracleParameter("myOutputParameter", OracleDbType.Decimal), ParameterDirection.ReturnValue);
    cmd.ExecuteNonQuery(); // an INSERT is always a Non Query
    return Convert.ToDecimal(cmd.Parameters["myOutputParameter"].Value);
}
Christian13467
A: 

Be careful with

SCOPE_IDENTITY () returns the last generated ID in your transaction, if the ID is generated in a nested Transaction you need to use IDENTITY (sorry that i cant add the double at sign before them whyever here in the editor !?)

Johannes Rudolph
I'm using Oracle, not sql server!
andrecarlucci
sorry, didnt get that one right
Johannes Rudolph
+1  A: 

Oracle uses sequences as for his identity columns, if we may say so.

If you have set a sequence for your table primary key, you also have to write a trigger that will insert the Sequence.NextValue or so into your primary key field.

Assuming that you are already familiar with this concept, simply query your sequence, then you will get your answer. What is very practiced in Oracle is to make yourself a function which will return an INT, then within your function, you perform your INSERT. Assuming that you have setup your trigger correctly, you will then be able to return the value of your sequence by querying it.

Here's an instance:

CREATE TABLE my_table (
    id_my_table INT PRIMARY KEY
    description VARCHAR2(100) NOT NULL
)

CREATE SEQUENCE my_table_seq
   MINVALUE 1
   MAXVALUE 1000
   START WITH 1
   INCREMENT BY 2
   CACHE 5;

If you want to manage the auto-increment yourself, here's how:

INSERT INTO my_table (
    id_my_table,
    description
) VALUES (my_table_seq.NEXTVAL, "Some description");
COMMIT;

On the other hand, if you wish not to care about the PRIMARY KEY increment, you may proceed with a trigger.

CREATE OR REPLACE TRIGGER my_table_insert_trg
    BEFORE INSERT ON my_table FOR EACH ROW
BEGIN
    SELECT my_table_seq.NEXTVAL INTO :NEW.id_my_table FROM DUAL;
END;

Then, when you're inserting, you simply type the INSERT statement as follows:

INSERT INTO my_table (description) VALUES ("Some other description");
COMMIT;

After an INSERT, I guess you'll want to

SELECT my_table_seq.CURRVAL

or something like this to select the actual value of your sequence.

Here are some links to help:

http://www.orafaq.com/wiki/Sequence

http://www.orafaq.com/wiki/AutoNumber_and_Identity_columns

Hope this helps!

Will Marcouiller
Hi Will,Nice, I didn't think about seq.CURRVAL. But is this save? I mean, if someone inserts a row between my two calls (insert, select)?
andrecarlucci
Crazy Joe Malloy
Oracle will perform the inserts in a sequential manner. Once it got through the first INSERT statement and returned the new current sequence's value, it will perform the other insert.As stated by Mr. Crazy Joe Malloy, that is no matter what the way of doing it anyway. :)We must not forget that Oracle works in a transactional way. So, no NEXTVALUE will be selected from the sequence as long as the INSERT statement is not COMMITed.In anyway, if I remember correctly, there's somekind of lock somewhere (TABLE or SEQUENCE) while performing the transaction.
Will Marcouiller