Is there a mechanism to get last inserted ID in Oracle 12c Enterprise edition by using SQL command?
In DB2 world, I would use:
SELECT IDENTITY_VAL_LOCAL() AS IDENTITY FROM SYSIBM.SYSDUMMY1
This would get me the last generated ID from current connection (session). This would mean that no matter if other inserts occur from other users (or same user but in different session) I would get the latest ID only from current session.
The only answer I could find for Oracle was the one using anonymous block.
DECLARE
V_ID NUMBER;
BEGIN
INSERT INTO OBJECT_EXAMPLE(NAME) VALUES ('Some name') returning ID into V_ID;
DBMS_OUTPUT.put_line(V_ID);
END;
However, this does not return result set. Since I'm using IBM BPM product I cannot define output parameter when executing anonymous block (I get "OUT parameters are only valid when used with a call operation"). Also, I cannot get "output" section like in DBeaver (I get empty record).
So what I really need is:
something that can insert a row into a table and get the latest ID form that table (or latest generated id from session) but only for that opened connection
or
something that acts like select but also does the insert
Oracle tables with automatically assigned unique integer columns use sequence objects to generate those unique values.
Look at the table definition or your INSERT query. One of them will show you the name of a sequence object for the unique id column.
Then use the sequence, via sequence.nextval, to create a unique id to INSERT into a table.
Then immediately do SELECT sequence.currval FROM dual to get the latest value, right after using the sequence to assign a unique value. For race-condition-safe operations do it placing the SELECT in a transaction with the INSERT.
This sequence stuff is often used in a series of INSERT operations something like this.
INSERT INTO person (person_id, given, surname, title)
VALUES (personid.nextval, 'Larry', 'Ellison', 'boss');
INSERT INTO phone (phone_id, person_id, type, value)
VALUES (phoneid.nextval, personid.currval, 'home', '555-1212');
INSERT INTO phone (phone_id, person_id, type, value)
VALUES (phoneid.nextval, personid.currval, 'office', '555-3434');
This gets us a person row with two associated phone rows. Notice the use of personid.currval for both phone rows.
Related
I have a rather complicated (at least for me) stored procedure to write that needs to handle multiple scenarios coming from the front end.
The frontend is passing 2 parameters that has values like this
#Levelmarker= (1234515-564546-65454,4654342-154658-56767,5465489-546549-65456)
These are GUIDS that are comma separated.
#`UserNameId= (5797823-65432143-65451213)
GUID of the user that entered this data on the front end
The values need to go to a table that has the following structure:
CREATE TABLE LevelTable
(
LevelId uniqueidentifier NOT NULL
LevelMarker uniqueidentiriet NOT NULL
UserName uniqueidentifier NOT NULL
);
I want the value to go into the table like this:
LevelId Levelmarker UserName
--------------------------------------------------------
NEWID() 1234515-564546-65454 5797823-654321-65451
NEWID() 4654342-154658-56767 5797823-654321-65451
NEWID() 5465489-546549-65456 5797823-654321-65451
Here are the scenarios the stored procedure should handle.
Once the levelmarkers are inserted into the table, if the same user comes back and wants to add additional Levelmarkers, the front end will pass the old values and the new ones as so: (1234515-564546-65454,4654342-154658-56767,5465489-546549-65456,1332245-9852135-7841265).
My stored procedure should recognize that I already have the first three Levelmarkers in the table and should only insert the new ones.
If the same user decides to delete values from before, lets say two values as an example, the front end will pass me the values (1234515-564546-65454,4654342-154658-56767). The stored procedure should recognize that the user has deleted two values and should delete the same values from the table and keep the non deleted ones.
If the user deletes some values and inserts a new ones, then the stored procedure should recognize the ones to delete and insert the new ones.
What is the best approach to this problem?
I think you can do this in a single query, using string_split() and a merge statement:
merge leveltable t
using (
select value levelmarker, #UserNameId username
from string_split(#LeveMarker, ',')
) s
on (s.levelmarker = t.levelmarker and s.username = t.username)
when not matched by target
then insert (leveid, levelmarker, username)
values (newid(), s.levelmarker, s.username)
when not matched by source
then delete
In the using clause, we split the #LevelMarker parameter into new rows, and associate the given #UserNameId. Then, the merge statement checks if each combination already exists in the target table, and creates or deletes rows accordingly.
SQL Server 2017 (In Azure) - when I need to create a new client in our clients database, I have to run three separate queries, and in between each query, do a lookup to be able to populate a part of the next query. I'd like to see if there is a way to combine all this into one query, or, parameterized stored procedure:
All of this takes place in the same database called Clients:
Step 1 - Create the client record in dbo.clients:
INSERT INTO dbo.clients
(ClientGuid, Name, Permissions)
VALUES
(NEWID(), 'Contoso', 1)
Step 2 - Get the Primary Key which was auto-created in Step 1:
SELECT ClientKey from dbo.clients
WHERE Name = 'Contoso'
Now write down the primary key (ClientKey) from that record, we'll say 12345678
Step 3 - Create a new billing code in the dbo.billingcodes table:
INSERT INTO dbo.billingcodes
(BillingCodeGuid, ClientKey, Name, ScoreId)
VALUES
(NEWID(), 12345678, 'Contoso Production Billing Code', 1)
How can I combine all this into one query or parameterized stored procedure where all I have to enter in are the two names from step 1 and 3 (assume the Permissions and ScoreId integers are always going to be 1) and also get an output at the end of the process of the created values for dbo.clients.ClientKey and dbo.billingcodes.BillingCodeGuid?
You could create a procedure that consists of both inserts with a line in between to get the ID of the inserted client. Assign the ID to a variable and pass it in to the second part.
See this post about some different ways about getting the inserted record’s ID Best way to get identity of inserted row?
You could do it by using procedure. You may find this link for creating procedure in SQL Server Link.
In case of Procedure , need to insert your data into first table. Then using IDENT_CURRENT (Ident_Current) you'll get your last inserted id from table, which will further use to insert it into next table.
So this is a continuation of post:
Best way to get identity of inserted row?
That post proposes, and I agree, to use Inserted feature to safely return inserted id column(s).
While implementing this feature, it seems SqlClient of the .net framework does not support this feature, and fails while trying to execute command, I get the following exception:
System.Data.SqlClient.SqlException: 'Cannot find either column "INSERTED" or the user-defined function or aggregate "INSERTED.Id", or the name is ambiguous.'
I'm just using:
return (T)command.ExecuteScalar();
Where the query is:
INSERT INTO MyTable
OUTPUT INSERTED.Id
(Description)
VALUES (#Description)
And the table just contains
ID (identity int)
Description (varchar(max))
If impossible to do, is there other safe way without using variables in the middle that might affect performance?
Thanks
You are doing everything correctly, but you have misplaced the OUTPUT clause: it goes after the list of columns and before the VALUES, i.e.
INSERT INTO MyTable (Description)
OUTPUT INSERTED.Id
VALUES (#Description)
In SQL Server, i am inserting multiple records into table using batch update. How do i get back the ID's (unique primary key) which is being created after batch update?
If I insert one record, I can get the last inserted using IDENT(tableName). I am not sure how to get if I do batch update. Please help.
For example, I have student table, with ROLE NO and NAME. ROLE NO is auto incremented by 1, as soon I insert the names into DB using java program. I will add 3 rows at a time using batch update from my java code. In DB, it gets added with ROLE NO 2, 3 and 4. How do I get these newly generated ID in my java program, please help
I tried getting ids using getgeneratedkeys method after I do executebatch. I get exception. Is batch update + get generated keys supported.?
In SQL Server when you do an insert there is an extra option your query; OUTPUT. This will let you capture back the data you inserted into the table - including your id's. You have to insert them into a temporary table; so something like this (with your table/ column names will get you there.
declare #MyNewRoles Table (Name, RoleNo)
insert into tblMyTable
(Name)
Select
Name
Output
inserted.Name, Inserted.RoleNo
into #MyNewRoles
From tblMyTableOfNames
select * from #MyNewRoles
If you don't mind adding a field to your table, you could generate a unique ID for each batch transaction (for example, a random UUID), and store that in the table as well. Then, to find the IDs associated with a given transaction you would just need something like
select my_id from my_table where batch_id = ?
I'm trying to get a the key-value back after an INSERT-statement.
Example:
I've got a table with the attributes name and id. id is a generated value.
INSERT INTO table (name) VALUES('bob');
Now I want to get the id back in the same step. How is this done?
We're using Microsoft SQL Server 2008.
No need for a separate SELECT...
INSERT INTO table (name)
OUTPUT Inserted.ID
VALUES('bob');
This works for non-IDENTITY columns (such as GUIDs) too
Use SCOPE_IDENTITY() to get the new ID value
INSERT INTO table (name) VALUES('bob');
SELECT SCOPE_IDENTITY()
http://msdn.microsoft.com/en-us/library/ms190315.aspx
INSERT INTO files (title) VALUES ('whatever');
SELECT * FROM files WHERE id = SCOPE_IDENTITY();
Is the safest bet since there is a known issue with OUTPUT Clause conflict on tables with triggers. Makes this quite unreliable as even if your table doesn't currently have any triggers - someone adding one down the line will break your application. Time Bomb sort of behaviour.
See msdn article for deeper explanation:
http://blogs.msdn.com/b/sqlprogrammability/archive/2008/07/11/update-with-output-clause-triggers-and-sqlmoreresults.aspx
Entity Framework performs something similar to gbn's answer:
DECLARE #generated_keys table([Id] uniqueidentifier)
INSERT INTO Customers(FirstName)
OUTPUT inserted.CustomerID INTO #generated_keys
VALUES('bob');
SELECT t.[CustomerID]
FROM #generated_keys AS g
JOIN dbo.Customers AS t
ON g.Id = t.CustomerID
WHERE ##ROWCOUNT > 0
The output results are stored in a temporary table variable, and then selected back to the client. Have to be aware of the gotcha:
inserts can generate more than one row, so the variable can hold more than one row, so you can be returned more than one ID
I have no idea why EF would inner join the ephemeral table back to the real table (under what circumstances would the two not match).
But that's what EF does.
SQL Server 2008 or newer only. If it's 2005 then you're out of luck.
There are many ways to exit after insert
When you insert data into a table, you can use the OUTPUT clause to
return a copy of the data that’s been inserted into the table. The
OUTPUT clause takes two basic forms: OUTPUT and OUTPUT INTO. Use the
OUTPUT form if you want to return the data to the calling application.
Use the OUTPUT INTO form if you want to return the data to a table or
a table variable.
DECLARE #MyTableVar TABLE (id INT,NAME NVARCHAR(50));
INSERT INTO tableName
(
NAME,....
)OUTPUT INSERTED.id,INSERTED.Name INTO #MyTableVar
VALUES
(
'test',...
)
IDENT_CURRENT: It returns the last identity created for a particular table or view in any session.
SELECT IDENT_CURRENT('tableName') AS [IDENT_CURRENT]
SCOPE_IDENTITY: It returns the last identity from a same session and the same scope. A scope is a stored procedure/trigger etc.
SELECT SCOPE_IDENTITY() AS [SCOPE_IDENTITY];
##IDENTITY: It returns the last identity from the same session.
SELECT ##IDENTITY AS [##IDENTITY];
##IDENTITY Is a system function that returns the last-inserted identity value.
There are multiple ways to get the last inserted ID after insert command.
##IDENTITY : It returns the last Identity value generated on a Connection in current session, regardless of Table and the scope of statement that produced the value
SCOPE_IDENTITY(): It returns the last identity value generated by the insert statement in the current scope in the current connection regardless of the table.
IDENT_CURRENT(‘TABLENAME’) : It returns the last identity value generated on the specified table regardless of Any connection, session or scope. IDENT_CURRENT is not limited by scope and session; it is limited to a specified table.
Now it seems more difficult to decide which one will be exact match for my requirement.
I mostly prefer SCOPE_IDENTITY().
If you use select SCOPE_IDENTITY() along with TableName in insert statement, you will get the exact result as per your expectation.
Source : CodoBee
The best and most sure solution is using SCOPE_IDENTITY().
Just you have to get the scope identity after every insert and save it in a variable because you can call two insert in the same scope.
ident_current and ##identity may be they work but they are not safe scope. You can have issues in a big application
declare #duplicataId int
select #duplicataId = (SELECT SCOPE_IDENTITY())
More detail is here Microsoft docs
You can use scope_identity() to select the ID of the row you just inserted into a variable then just select whatever columns you want from that table where the id = the identity you got from scope_identity()
See here for the MSDN info http://msdn.microsoft.com/en-us/library/ms190315.aspx
Recommend to use SCOPE_IDENTITY() to get the new ID value, But NOT use "OUTPUT Inserted.ID"
If the insert statement throw exception, I except it throw it directly. But "OUTPUT Inserted.ID" will return 0, which maybe not as expected.
This is how I use OUTPUT INSERTED, when inserting to a table that uses ID as identity column in SQL Server:
'myConn is the ADO connection, RS a recordset and ID an integer
Set RS=myConn.Execute("INSERT INTO M2_VOTELIST(PRODUCER_ID,TITLE,TIMEU) OUTPUT INSERTED.ID VALUES ('Gator','Test',GETDATE())")
ID=RS(0)
You can append a select statement to your insert statement.
Integer myInt =
Insert into table1 (FName) values('Fred'); Select Scope_Identity();
This will return a value of the identity when executed scaler.
* Parameter order in the connection string is sometimes important. * The Provider parameter's location can break the recordset cursor after adding a row. We saw this behavior with the SQLOLEDB provider.
After a row is added, the row fields are not available, UNLESS the Provider is specified as the first parameter in the connection string. When the provider is anywhere in the connection string except as the first parameter, the newly inserted row fields are not available. When we moved the the Provider to the first parameter, the row fields magically appeared.
After doing an insert into a table with an identity column, you can reference ##IDENTITY to get the value:
http://msdn.microsoft.com/en-us/library/aa933167%28v=sql.80%29.aspx