Cannot insert data into a table which has an identity constraint [duplicate] - sql
I have the below error when I execute the following script. What is the error about, and how it can be resolved?
Insert table(OperationID,OpDescription,FilterID)
values (20,'Hierachy Update',1)
Error:
Server: Msg 544, Level 16, State 1, Line 1
Cannot insert explicit value for identity column in table 'table' when IDENTITY_INSERT is set to OFF.
You're inserting values for OperationId that is an identity column.
You can turn on identity insert on the table like this so that you can specify your own identity values.
SET IDENTITY_INSERT Table1 ON
INSERT INTO Table1
/*Note the column list is REQUIRED here, not optional*/
(OperationID,
OpDescription,
FilterID)
VALUES (20,
'Hierachy Update',
1)
SET IDENTITY_INSERT Table1 OFF
don't put value to OperationID because it will be automatically generated. try this:
Insert table(OpDescription,FilterID) values ('Hierachy Update',1)
Simply If you getting this error on SQL server then run this query-
SET IDENTITY_INSERT tableName ON
This is working only for a single table of database
e.g If the table name is student then query look like this:
SET IDENTITY_INSERT student ON
If you getting this error on your web application or you using entity framework then first run this query on SQL server and Update your entity model (.edmx file) and build your project and this error will be resolved
Be very wary of setting IDENTITY_INSERT to ON. This is a poor practice unless the database is in maintenance mode and set to single user. This affects not only your insert, but those of anyone else trying to access the table.
Why are you trying to put a value into an identity field?
In your entity for that table, add the DatabaseGenerated attribute above the column for which identity insert is set:
Example:
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int TaskId { get; set; }
There are basically 2 different ways to INSERT records without having an error:
1) When the IDENTITY_INSERT is set OFF. The PRIMARY KEY "ID" MUST NOT BE PRESENT
2) When the IDENTITY_INSERT is set ON. The PRIMARY KEY "ID" MUST BE PRESENT
As per the following example from the same Table created with an IDENTITY PRIMARY KEY:
CREATE TABLE [dbo].[Persons] (
ID INT IDENTITY(1,1) PRIMARY KEY,
LastName VARCHAR(40) NOT NULL,
FirstName VARCHAR(40)
);
1) In the first example, you can insert new records into the table without getting an error when the IDENTITY_INSERT is OFF. The PRIMARY KEY "ID" MUST NOT BE PRESENT from the "INSERT INTO" Statements and a unique ID value will be added automatically:. If the ID is present from the INSERT in this case, you will get the error "Cannot insert explicit value for identify column in table..."
SET IDENTITY_INSERT [dbo].[Persons] OFF;
INSERT INTO [dbo].[Persons] (FirstName,LastName)
VALUES ('JANE','DOE');
INSERT INTO Persons (FirstName,LastName)
VALUES ('JOE','BROWN');
OUTPUT of TABLE [dbo].[Persons] will be:
ID LastName FirstName
1 DOE Jane
2 BROWN JOE
2) In the Second example, you can insert new records into the table without getting an error when the IDENTITY_INSERT is ON. The PRIMARY KEY "ID" MUST BE PRESENT from the "INSERT INTO" Statements as long as the ID value does not already exist: If the ID is NOT present from the INSERT in this case, you will get the error "Explicit value must be specified for identity column table..."
SET IDENTITY_INSERT [dbo].[Persons] ON;
INSERT INTO [dbo].[Persons] (ID,FirstName,LastName)
VALUES (5,'JOHN','WHITE');
INSERT INTO [dbo].[Persons] (ID,FirstName,LastName)
VALUES (3,'JACK','BLACK');
OUTPUT of TABLE [dbo].[Persons] will be:
ID LastName FirstName
1 DOE Jane
2 BROWN JOE
3 BLACK JACK
5 WHITE JOHN
you can simply use This statement for example if your table name is School.
Before insertion make sure identity_insert is set to ON and after insert query turn identity_insert OFF
SET IDENTITY_INSERT School ON
/*
insert query
enter code here
*/
SET IDENTITY_INSERT School OFF
Note that if you are closing each line with ;, the SET IDENTITY_INSERT mytable ON command will not hold for the following lines.
i.e.
a query like
SET IDENTITY_INSERT mytable ON;
INSERT INTO mytable (VoucherID, name) VALUES (1, 'Cole');
Gives the error
Cannot insert explicit value for identity column in table 'mytable' when IDENTITY_INSERT is set to OFF.
But a query like this will work:
SET IDENTITY_INSERT mytable ON
INSERT INTO mytable (VoucherID, name) VALUES (1, 'Cole')
SET IDENTITY_INSERT mytable OFF;
It seems like the SET IDENTITY_INSERT command only holds for a transaction, and the ; will signify the end of a transaction.
If you are using liquibase to update your SQL Server, you are likely trying to insert a record key into an autoIncrement field. By removing the column from the insert, your script should run.
<changeSet id="CREATE_GROUP_TABLE" >
<createTable tableName="GROUP_D">
<column name="GROUP_ID" type="INTEGER" autoIncrement="true">
<constraints primaryKey="true"/>
</column>
</createTable>
</changeSet>
<changeSet id="INSERT_UNKNOWN_GROUP" >
<insert tableName="GROUP_D">
<column name="GROUP_ID" valueNumeric="-1"/>
...
</insert>
</changeSet>
everyone comment about SQL, but what happened in EntityFramework? I spent reading the whole post and no one solved EF. So after a few days a found solution:
EF Core in the context to create the model there is an instruction like this: modelBuilder.Entity<Cliente>(entity => { entity.Property(e => e.Id).ValueGeneratedNever();
this produces the error too, solution: you have to change by ValueGeneratedOnAdd() and its works!
There is pre-mentioned OperationId in your query which should not be there as it is auto increamented
Insert table(OperationID,OpDescription,FilterID)
values (20,'Hierachy Update',1)
so your query will be
Insert table(OpDescription,FilterID)
values ('Hierachy Update',1)
The best solution is to use annotation GeneratedValue(strategy = ...), i.e.
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column ...
private int OperationID;
it says, that this column is generated by database using IDENTITY strategy and you don't need to take care of - database will do it.
Another situation is to check that the Primary Key is the same name as with your classes where the only difference is that your primary key has an 'ID' appended to it or to specify [Key] on primary keys that are not related to how the class is named.
This occurs when you have a (Primary key) column that is not set to Is Identity to true in SQL and you don't pass explicit value thereof during insert. It will take the first row, then you wont be able to insert the second row, the error will pop up. This can be corrected by adding this line of code [DatabaseGenerated(DatabaseGeneratedOption.Identity)] in your PrimaryKey column and make sure its set to a data type int. If the column is the primary key and is set to IsIDentity to true in SQL there is no need for this line of code [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
this also occurs when u have a column that is not the primary key, in SQL that is set to Is Identity to true, and in your EF you did not add this line of code [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
If you're having this issue while using an sql-server with the sequelize-typescript npm make sure to add #AutoIncrement to ID column:
#PrimaryKey
#AutoIncrement
#Column
id!: number;
I solved this problem by creating a new object every time I want to add anything to the database.
In my case I was having set another property as key in context for my modelBuilder.
modelBuilder.Entity<MyTable>().HasKey(t => t.OtherProp);
I had to set the proper id
modelBuilder.Entity<MyTable>().HasKey(t => t.Id);
EF Core 3.x
Referencing Leniel Maccaferri, I had a table with an Autoincrementing attribute called ID(original primary key) and another attribute called Other_ID(The new primary Key). Originally ID was the primary key but then Other_ID needed to be the new Primary key. Since ID was being used in other parts of the application I could not just remove it from Table. Leniel Maccaferri solution only worked for me after I added the following snippet:
entity.HasKey(x => x.Other_ID);
entity.Property(x => x.ID).ValueGeneratedOnAdd();
Full Code snippet Below (ApplicationDbContext.cs):
protected override void OnModelCreating(ModelBuilder builder)
{
builder.ApplyConfigurationsFromAssembly(Assembly.GetExecutingAssembly());
base.OnModelCreating(builder);
builder.Entity<tablename>(entity =>
{
entity.HasKey(x => x.Other_ID);
entity.Property(x => x.ID).ValueGeneratedOnAdd();
entity.HasAlternateKey(x => new { x.Other_ID, x.ID });
});
}
First Go to the required table name
Step 2 -> right click on the table name
step 3 --> Select Design
step 4 --> Click on the column name
step 5) go to the column properties then Set No to the Identity Specification
[Note: After insert to the explicit value if you want you can revert back to identity specification true then again it will generate the value]
if you using SQL server management studio you can use below method
Step 1)
step 2)
Even if everything was correct, this error can appear if the data type of Identity column is not int or long. I had identity column as decimal, although I was only saving int values (my bad). Changing data type in both database and underlying model fixed the issue for me.
Put break point on your [HttpPost] method and check what value is being passed to Id property. If it is other than zero then this error will occur.
First thing first...
You need to know why you are getting the error in the first place.
Lets take a simple HttpPost of JSON Data that looks like this:
{
"conversationID": 1,
"senderUserID": 1,
"receiverUserID": 2,
"message": "I fell for the wrong man!",
"created":"2022-02-14T21:18:11.186Z"
}
If you generated your database using Entity framework core while connecting to SQLServer or any other database server, the database automatically takes the responsibility of updating and auto-generating the Key/Unique identifier of the Identity Column, which in most cases is an integer value it auto-increments.
To safely post your data using the in-built conventions which keeps you at a safer end, just remove the ID field from the data you want to send to the database, and let the database engine and ef-core do the heavy lifting which they are designed to do.
So the proper way to post the data would be:
{
"senderUserID": 1,
"receiverUserID": 2,
"message": "I fell for the wrong man!",
"created":"2022-02-14T21:18:11.186Z"
}
You would notice I took out the ConversationID.
You can learn more about entity framework on this website : https://entityframeworkcore.com
I hope you stick more to conventions than configuration in your apps. Knowing how to do things with already proven standards and conventions will save you a lot of working hours.
And if you are using Oracle SQL Developer to connect, remember to add /sqldev:stmt/
/sqldev:stmt/ set identity_insert TABLE on;
I'm not sure what the use for the "Insert Table" is, but if you're just trying to insert some values try:
Insert Into [tablename] (OpDescription,FilterID)
values ('Hierachy Update',1);
I had the same error message come up, but I think this should work. The ID should auto-increment automatically as long as it's a primary key.
In my CASE I was inserting more character than defined in table.
In My Table column was defined with nvarchar(3) and I was passing more than 3 characters and same ERROR message was coming .
Its not answer but may be in some case problem is similar
im using asp.net core 5.0 and i get that error. i get that error because i was adding another data and triggering the other .SaveChanges() method like below :
_unitOfWorkVval.RepositoryVariantValue.Create(variantValue);
int request = HttpContext.Response.StatusCode;
if (request == 200)
{
int tryCatch = _unitOfWorkCVar.Complete();
if (tryCatch != 0)
{
productVariant.CategoryVariantID = variantValue.CategoryVariantID;
productVariant.ProductID = variantValue.ProductID;
productVariant.CreatedDate = DateTime.Now;
_unitOfWorkProductVariant.RepositoryProductVariant.Create(productVariant);
_unitOfWorkVval.RepositoryVariantValue.Create(variantValue);
int request2 = HttpContext.Response.StatusCode;
if(request==200)
{
int tryCatch2=_unitOfWorkProductVariant.Complete();//The point where i get that error
}///.......
Had the same issue using Entity Framework with a model like this (I simplified the original code):
public class Pipeline
{
public Pipeline()
{
Runs = new HashSet<Run>();
}
public int Id {get; set;}
public ICollection<Run> Runs {get;set;}
}
public class Run
{
public int Id {get; set;}
public int RequestId {get; set;}
public Pipeline Pipeline {get;set;}
}
The Run has a many-to-1 relation to the Pipeline (one Pipeline can run multiple times)
In my RunService I have injected the DbContex as context. The DbContext had a Runs DbSet. I implemented this method in the RunService:
public async Task<Run> CreateAndInit(int requestId, int pplId)
{
Pipeline pipeline = await pipelineService.Get(pplId).FirstOrDefaultAsync().ConfigureAwait(false);
Run newRun = new Run {RequestId = requestId, Pipeline = pipeline};
context.Runs.Add(newRun);
await context.SaveChangesAsync().ConfigureAwait(false); // got exception in this line
return newRun;
}
As the method executed, I got this exception:
Exception has occurred: CLR/Microsoft.EntityFrameworkCore.DbUpdateException
Exception thrown: 'Microsoft.EntityFrameworkCore.DbUpdateException' in System.Private.CoreLib.dll: 'An error occurred while updating the entries. See the inner exception for details.'
Inner exceptions found, see $exception in variables window for more details.
Innermost exception Microsoft.Data.SqlClient.SqlException : Cannot insert explicit value for identity column in table 'Pipelines' when IDENTITY_INSERT is set to OFF.
For me, the solution was to separate the creation of the object and relation
public async Task<Run> CreateAndInit(int requestId, int pplId)
{
Pipeline pipeline = await pipelineService.Get(pplId).FirstOrDefaultAsync().ConfigureAwait(false);
Run newRun = new Run {RequestId = requestId};
context.Runs.Add(newRun);
newRun.Pipeline = pipeline; // set the relation separately
await context.SaveChangesAsync().ConfigureAwait(false); // no exception
return newRun;
}
In my case the problem was, that I specified the autoincrement ID by myself from the code when I tried to update the records.
After removing the ID property from new record creation, then everything worked fine.
You can not insert data in OperationID column when you set identity increment for this field.
Do not enter a value in this field, it will be set automatically.
Insert table(OpDescription,FilterID)
values ('Hierachy Update',1)
The problem raised from using non-typed DBContext or DBSet if you using Interface and implement method of savechanges in a generic way
If this is your case I propose to strongly typed DBContex for example
MyDBContext.MyEntity.Add(mynewObject)
then .Savechanges will work
Related
Insert into a table containing only identity column
I have the following table : CREATE TABLE Seq2 (val INT NOT NULL IDENTITY); How to populate this table knowing that I tried this : INSERT INTO Seq2(val) VALUES (1) I have the following error : Cannot insert explicit value for identity column in table 'Seq2' when IDENTITY_INSERT is set to OFF.
Having such a table seems completely pointless, if I must say. If the table has only an IDENTITY then it effectively holds no meaning, so there's no point it being there. That being said, if you did have such a table, you can INSERT values into the IDENTITY using DEFAULT VALUES: INSERT INTO dbo.Seq2 DEFAULT VALUES; INSERT INTO dbo.Seq2 DEFAULT VALUES; With a new table, this would create rows with the values 1 and 2. If you want to explicitly INSERT values into the table, then you're better off remove the IDENTITY option. Considering this is a new table, just DROP it and recreate it with the IDENTITY property: DROP TABLE dbo.Seq2; GO CREATE TABLE Seq2 (val INT NOT NULL); Having a table with a single IDENTITY column, that you're then going to define the results for really is pointless. Either don't use IDENTITY and define the values, or use IDENTITY and let SQL Server handle it.
SET IDENTITY_INSERT Seq2 ON INSERT INTO Seq2(val)VALUES (1) SET IDENTITY_INSERT Seq2 OFF
Simply, enable IDENTITY_INSERT for the table. That looks like this: SET IDENTITY_INSERT IdentityTable ON INSERT INTO Seq2(val) VALUES (1) SET IDENTITY_INSERT IdentityTable OFF Keep in mind : It can only be enabled on one table at a time. If you try to enable it on a second table while it is still enabled on a first table SQL Server will generate an error. When it is enabled on a table you must specify a value for the identity column. The user issuing the statement must own the object, be a system administrator (sysadmin role), be the database owner (dbo) or be a member of the db_ddladmin role in order to run the command. SELECT SCOPE_IDENTITY() // to get last identity value generated in the same session and scope SELECT ##IDENTITY // to get the last identity vaue generated in a session irrespective of scope
Insert statement with a NON-NULLABLE column
I have a SQL Server script that I'm using to insert some data into a database. I won't upload the whole script here just for space/time savings sake, but I will include the important bits. So here is the problem. I have a table that has a column for some loginhtml, this column is of a non-nullable type. I would like for this column to be left blank on this particular add so it can default back to the parent that I'm pointing it at. So here we have the declaration for this important portion: declare #loginTitle varchar(250), #loginHtml varchar(max) And here we have what it will be set to: set #loginHtml = null And here is the insert part that is inevitably going to fail: insert dbo.ApplicationLogin(ApplicationID, Title, Html) select #appID, #loginTitle, #loginHtml EDIT: How can I have this script "default" the loginhtml column to whatever the PARENT Application is? Is there some "IF" statement/clause that can be used to accomplish this?
As long as the column in non null, then you can't insert a null value into it. You could try setting it to a blank string or other default value. You could aslo select the parent's html and insert that instead. There is no way to skip over inserting any column.
As others have stated, if there is a Not Null constraint on the column, you are out of luck, but you could do if #loginhtml is null begin set #loginhtml = '' end Or change set #loginhtml = '' to lookup whatever the default in the parent application is. and you will write a blank instead of anything. You, obviously, run into whatever issues there will be with having no loginhtml, but if that's what you want that is what you want!
You can adjust your script: insert dbo.ApplicationLogin(ApplicationID, Title, Html) select #appID, #loginTitle, ISNULL(#loginHtml, '') Or adjust your table and add a default constraint: ALTER TABLE ApplicationLogin ADD DEFAULT (('')) FOR [Html];
I may not have mentioned this in the initial post, and I would like to apologize for that. But the way the database is set up, is applications can have parent applications, so setting the loginhtml to the parent application and "technically" skipping adding it to the new application can be done by doing this: if(#loginHtml is not null) begin insert dbo.ApplicationLogin(ApplicationID, Title, Html) select #appID, #loginTitle, #loginHtml end This runs successfully and makes the "#loginhtml" default to whatever the parent application has set for that value.
NHibernate - Insert with identity_insert ON
I have an issue where I am trying to re-insert an entity into my database. It is illustrated with the following unit test: // entity mapped to dbo.IdentityInsertTest table // dbo.IdentityInsertTest has an IDENTITY Primary Key, Id var id = (long)NHibernateSession1.Save(new IdentityInsertTest()); NHibernateSession1.Flush(); // delete previously created row ExecuteNonQuery("DELETE FROM dbo.IdentityInsertTest"); try { // set entity insert off so that I can re-insert NHibernateSession2.CreateSQLQuery("SET IDENTITY_INSERT dbo.IdentityInsertTest ON").UniqueResult(); // re-create deleted row with explicit Id NHibernateSession2.Save(new IdentityInsertTest { Id = id }); NHibernateSession2.Flush(); Assert.AreEqual(1, ExecuteScalar("SELECT COUNT(1) FROM dbo.IdentityInsertTest")); // this assert fails: expected 1, actual 2 Assert.AreEqual(id, ExecuteScalar("SELECT TOP 1 [Id] FROM dbo.IdentityInsertTest")); } finally { NHibernateSession2.CreateSQLQuery("SET IDENTITY_INSERT dbo.IdentityInsertTest OFF").UniqueResult(); } My mapping is quite simple: <class name="IdentityInsertTest" table="IdentityInsertTest"> <id name="Id" type="long"> <generator class="native" /> </id> <property name="Data" type="int" not-null="false" /> </class> The issue as far as I can see it is that the NHibernate generator is still somehow invoking the identity generation from SQL, even though I have switched it off. Is there any way around this? Edit: I had originally forgotten to execute "UniqueResult()" when setting IDENTITY_INSERT, but this does not seem to be the root of the error. Still getting the same results
you are not actually executing your SQLQuery, this should do the trick IQuery sqlQry = NHibernateSession2.CreateSQLQuery("SET IDENTITY_INSERT dbo.IdentityInsertTest ON"); object ret = sqlQry.UniqueResult();
Just wondering your logic here regarding deleting/re-adding as opposed to NOT deleting but just updating.... However if NHibernate is getting in your way and you can't change remove Identity column then there are some hideous work arounds... If you want to add a record at the bottom then you could try this:- var sql = "DECLARE #id long = 0; SELECT #id = MAX(Id) + 1 FROM IdentityInsertTest; DBCC CHECKIDENT(IdentityInsertTest, RESEED, #id);"; NHibernateSession2.CreateSqlQuery(sql).ExecuteUpdate(); ... now save the entity normally OR If you want to add a record somewhere in the middle of the table then you will have to build the SQL by hand:- var sql = "SET IDENTITY_INSERT dbo.IdentityInsertTest ON; INSERT INTO IdentityInsertTest(Id, Data) Values (:id, :data) VALUES (:id, :data); SET IDENTITY_INSERT dbo.IdentityInsertTest OFF;"; NHibernateSession2.CreateSqlQuery(sql) .SetInt64("id", id) .SetInt32("data", data) .ExecuteUpdate();
NOTE: I have marked this as the answer as it directly answers the question, however, in the end I went with a soft delete option as commented above The problem was that I wasn't specifying the Id explicitly in the save method even if I had, the set identity_insert would have been executed in another query. That one is fixed by using a transaction // entity mapped to dbo.IdentityInsertTest table // dbo.IdentityInsertTest has an IDENTITY Primary Key, Id var id = (long)NHibernateSession1.Save(new IdentityInsertTest()); NHibernateSession1.Flush(); // delete previously created row ExecuteNonQuery("DELETE FROM dbo.IdentityInsertTest"); try { NHibernate.ITransaction txn; using (txn = SelectSession1.BeginTransaction()) { // set entity insert off so that I can re-insert NHibernateSession2.CreateSQLQuery("SET IDENTITY_INSERT dbo.IdentityInsertTest ON").UniqueResult(); // re-create deleted row with explicit Id NHibernateSession2.Save(new IdentityInsertTest(), id); NHibernateSession2.Flush(); txn.Commit(); } Assert.AreEqual(1, ExecuteScalar("SELECT COUNT(1) FROM dbo.IdentityInsertTest")); // this assert fails: expected 1, actual 2 Assert.AreEqual(id, ExecuteScalar("SELECT TOP 1 [Id] FROM dbo.IdentityInsertTest")); } finally { NHibernateSession2.CreateSQLQuery("SET IDENTITY_INSERT dbo.IdentityInsertTest OFF").UniqueResult(); }
Choose another key generation strategy, what you're attempting to do is a really bad idea. An identity column is an artificial primary key and it should not have any meaning.
I have to say, this issue blocked me long time. Even through I exec sql "SET IDENTITY_INSERT dbo.IdentityInsertTest ON" before and then run Nihbernate code, it was stil does not work. there are 2 points need to take more attation. First, you must use Transaction in you code. NHibernate.ITransaction txn; using (txn = SelectSession1.BeginTransaction()) { NHibernateSession2.CreateSQLQuery("SET IDENTITY_INSERT dbo.IdentityInsertTest ON").UniqueResult(); ... NHibernateSession2.Flush(); txn.Commit(); } Second, you must use "Id(x => x.Id).GeneratedBy.Assigned().Column("Id");" in your mapping section.
Trying to insert a row using stored procedured with a parameter binded to an expression
Environment: asp.net 3.5 (C# and VB) , Ms-sql server 2005 express Tables Table:tableUser ID (primary key) username Table:userSchedule ID (primary key) thecreator (foreign key = tableUser.ID) other fields I have created a procedure that accepts a parameter username and gets the userid and inserts a row in Table:userSchedule Problem: Using stored procedure with datalist control to only fetch data from the database by passing the current username using statement below works fine protected void SqlDataSourceGetUserID_Selecting(object sender, SqlDataSourceSelectingEventArgs e) { e.Command.Parameters["#CurrentUserName"].Value = Context.User.Identity.Name; } But while inserting using DetailsView it shows error Procedure or function OASNewSchedule has too many arguments specified. I did use protected void SqlDataSourceCreateNewSchedule_Selecting(object sender, SqlDataSourceSelectingEventArgs e) { e.Command.Parameters["#CreatedBy"].Value = Context.User.Identity.Name; } DetailsView properties: autogen fields: off, default mode: insert, it shows all the fields that may not be expected by the procedure like ID (primary key) not required in procedure and CreatedBy (user id ) field . So I tried removing the 2 fields from detailsview and shows error Cannot insert the value NULL into column 'CreatedBy', table 'D:\OAS\OAS\APP_DATA\ASPNETDB.MDF.dbo.OASTest'; column does not allow nulls. INSERT fails. The statement has been terminated. For some reason parameters value is not being set. Can anybody bother to understand this and help?
Ok my mistake, I didn't know how delegation works and what it was. Instead of SqlDataSourceCreateNewSchedule_Selecting(....) I should have used SqlDataSourceCreateNewSchedule_Inserting to modify the parameter after all the need was to set parameter while inserting not selecting.
How to get the identity of an inserted row?
How am I supposed to get the IDENTITY of an inserted row? I know about ##IDENTITY and IDENT_CURRENT and SCOPE_IDENTITY, but don't understand the implications or impacts attached to each. Can someone please explain the differences and when I would be using each?
##IDENTITY returns the last identity value generated for any table in the current session, across all scopes. You need to be careful here, since it's across scopes. You could get a value from a trigger, instead of your current statement. SCOPE_IDENTITY() returns the last identity value generated for any table in the current session and the current scope. Generally what you want to use. IDENT_CURRENT('tableName') returns the last identity value generated for a specific table in any session and any scope. This lets you specify which table you want the value from, in case the two above aren't quite what you need (very rare). Also, as #Guy Starbuck mentioned, "You could use this if you want to get the current IDENTITY value for a table that you have not inserted a record into." The OUTPUT clause of the INSERT statement will let you access every row that was inserted via that statement. Since it's scoped to the specific statement, it's more straightforward than the other functions above. However, it's a little more verbose (you'll need to insert into a table variable/temp table and then query that) and it gives results even in an error scenario where the statement is rolled back. That said, if your query uses a parallel execution plan, this is the only guaranteed method for getting the identity (short of turning off parallelism). However, it is executed before triggers and cannot be used to return trigger-generated values.
I believe the safest and most accurate method of retrieving the inserted id would be using the output clause. for example (taken from the following MSDN article) USE AdventureWorks2008R2; GO DECLARE #MyTableVar table( NewScrapReasonID smallint, Name varchar(50), ModifiedDate datetime); INSERT Production.ScrapReason OUTPUT INSERTED.ScrapReasonID, INSERTED.Name, INSERTED.ModifiedDate INTO #MyTableVar VALUES (N'Operator error', GETDATE()); --Display the result set of the table variable. SELECT NewScrapReasonID, Name, ModifiedDate FROM #MyTableVar; --Display the result set of the table. SELECT ScrapReasonID, Name, ModifiedDate FROM Production.ScrapReason; GO
I'm saying the same thing as the other guys, so everyone's correct, I'm just trying to make it more clear. ##IDENTITY returns the id of the last thing that was inserted by your client's connection to the database. Most of the time this works fine, but sometimes a trigger will go and insert a new row that you don't know about, and you'll get the ID from this new row, instead of the one you want SCOPE_IDENTITY() solves this problem. It returns the id of the last thing that you inserted in the SQL code you sent to the database. If triggers go and create extra rows, they won't cause the wrong value to get returned. Hooray IDENT_CURRENT returns the last ID that was inserted by anyone. If some other app happens to insert another row at an unforunate time, you'll get the ID of that row instead of your one. If you want to play it safe, always use SCOPE_IDENTITY(). If you stick with ##IDENTITY and someone decides to add a trigger later on, all your code will break.
The best (read: safest) way to get the identity of a newly-inserted row is by using the output clause: create table TableWithIdentity ( IdentityColumnName int identity(1, 1) not null primary key, ... ) -- type of this table's column must match the type of the -- identity column of the table you'll be inserting into declare #IdentityOutput table ( ID int ) insert TableWithIdentity ( ... ) output inserted.IdentityColumnName into #IdentityOutput values ( ... ) select #IdentityValue = (select ID from #IdentityOutput)
Add SELECT CAST(scope_identity() AS int); to the end of your insert sql statement, then NewId = command.ExecuteScalar() will retrieve it.
From MSDN ##IDENTITY, SCOPE_IDENTITY, and IDENT_CURRENT are similar functions in that they return the last value inserted into the IDENTITY column of a table. ##IDENTITY and SCOPE_IDENTITY will return the last identity value generated in any table in the current session. However, SCOPE_IDENTITY returns the value only within the current scope; ##IDENTITY is not limited to a specific scope. IDENT_CURRENT is not limited by scope and session; it is limited to a specified table. IDENT_CURRENT returns the identity value generated for a specific table in any session and any scope. For more information, see IDENT_CURRENT. IDENT_CURRENT is a function which takes a table as a argument. ##IDENTITY may return confusing result when you have an trigger on the table SCOPE_IDENTITY is your hero most of the time.
When you use Entity Framework, it internally uses the OUTPUT technique to return the newly inserted ID value DECLARE #generated_keys table([Id] uniqueidentifier) INSERT INTO TurboEncabulators(StatorSlots) OUTPUT inserted.TurboEncabulatorID INTO #generated_keys VALUES('Malleable logarithmic casing'); SELECT t.[TurboEncabulatorID ] FROM #generated_keys AS g JOIN dbo.TurboEncabulators AS t ON g.Id = t.TurboEncabulatorID WHERE ##ROWCOUNT > 0 The output results are stored in a temporary table variable, joined back to the table, and return the row value out of the table. Note: 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. This technique (OUTPUT) is only available on SQL Server 2008 or newer. Edit - The reason for the join The reason that Entity Framework joins back to the original table, rather than simply use the OUTPUT values is because EF also uses this technique to get the rowversion of a newly inserted row. You can use optimistic concurrency in your entity framework models by using the Timestamp attribute: 🕗 public class TurboEncabulator { public String StatorSlots) [Timestamp] public byte[] RowVersion { get; set; } } When you do this, Entity Framework will need the rowversion of the newly inserted row: DECLARE #generated_keys table([Id] uniqueidentifier) INSERT INTO TurboEncabulators(StatorSlots) OUTPUT inserted.TurboEncabulatorID INTO #generated_keys VALUES('Malleable logarithmic casing'); SELECT t.[TurboEncabulatorID], t.[RowVersion] FROM #generated_keys AS g JOIN dbo.TurboEncabulators AS t ON g.Id = t.TurboEncabulatorID WHERE ##ROWCOUNT > 0 And in order to retrieve this Timetsamp you cannot use an OUTPUT clause. That's because if there's a trigger on the table, any Timestamp you OUTPUT will be wrong: Initial insert. Timestamp: 1 OUTPUT clause outputs timestamp: 1 trigger modifies row. Timestamp: 2 The returned timestamp will never be correct if you have a trigger on the table. So you must use a separate SELECT. And even if you were willing to suffer the incorrect rowversion, the other reason to perform a separate SELECT is that you cannot OUTPUT a rowversion into a table variable: DECLARE #generated_keys table([Id] uniqueidentifier, [Rowversion] timestamp) INSERT INTO TurboEncabulators(StatorSlots) OUTPUT inserted.TurboEncabulatorID, inserted.Rowversion INTO #generated_keys VALUES('Malleable logarithmic casing'); The third reason to do it is for symmetry. When performing an UPDATE on a table with a trigger, you cannot use an OUTPUT clause. Trying do UPDATE with an OUTPUT is not supported, and will give an error: Cannot use UPDATE with OUTPUT clause when a trigger is on the table The only way to do it is with a follow-up SELECT statement: UPDATE TurboEncabulators SET StatorSlots = 'Lotus-O deltoid type' WHERE ((TurboEncabulatorID = 1) AND (RowVersion = 792)) SELECT RowVersion FROM TurboEncabulators WHERE ##ROWCOUNT > 0 AND TurboEncabulatorID = 1
I can't speak to other versions of SQL Server, but in 2012, outputting directly works just fine. You don't need to bother with a temporary table. INSERT INTO MyTable OUTPUT INSERTED.ID VALUES (...) By the way, this technique also works when inserting multiple rows. INSERT INTO MyTable OUTPUT INSERTED.ID VALUES (...), (...), (...) Output ID 2 3 4
##IDENTITY is the last identity inserted using the current SQL Connection. This is a good value to return from an insert stored procedure, where you just need the identity inserted for your new record, and don't care if more rows were added afterward. SCOPE_IDENTITY is the last identity inserted using the current SQL Connection, and in the current scope -- that is, if there was a second IDENTITY inserted based on a trigger after your insert, it would not be reflected in SCOPE_IDENTITY, only the insert you performed. Frankly, I have never had a reason to use this. IDENT_CURRENT(tablename) is the last identity inserted regardless of connection or scope. You could use this if you want to get the current IDENTITY value for a table that you have not inserted a record into.
ALWAYS use scope_identity(), there's NEVER a need for anything else.
One other way to guarantee the identity of the rows you insert is to specify the identity values and use the SET IDENTITY_INSERT ON and then OFF. This guarantees you know exactly what the identity values are! As long as the values are not in use then you can insert these values into the identity column. CREATE TABLE #foo ( fooid INT IDENTITY NOT NULL, fooname VARCHAR(20) ) SELECT ##Identity AS [##Identity], Scope_identity() AS [SCOPE_IDENTITY()], Ident_current('#Foo') AS [IDENT_CURRENT] SET IDENTITY_INSERT #foo ON INSERT INTO #foo (fooid, fooname) VALUES (1, 'one'), (2, 'Two') SET IDENTITY_INSERT #foo OFF SELECT ##Identity AS [##Identity], Scope_identity() AS [SCOPE_IDENTITY()], Ident_current('#Foo') AS [IDENT_CURRENT] INSERT INTO #foo (fooname) VALUES ('Three') SELECT ##Identity AS [##Identity], Scope_identity() AS [SCOPE_IDENTITY()], Ident_current('#Foo') AS [IDENT_CURRENT] -- YOU CAN INSERT SET IDENTITY_INSERT #foo ON INSERT INTO #foo (fooid, fooname) VALUES (10, 'Ten'), (11, 'Eleven') SET IDENTITY_INSERT #foo OFF SELECT ##Identity AS [##Identity], Scope_identity() AS [SCOPE_IDENTITY()], Ident_current('#Foo') AS [IDENT_CURRENT] SELECT * FROM #foo This can be a very useful technique if you are loading data from another source or merging data from two databases etc.
Create a uuid and also insert it to a column. Then you can easily identify your row with the uuid. Thats the only 100% working solution you can implement. All the other solutions are too complicated or are not working in same edge cases. E.g.: 1) Create row INSERT INTO table (uuid, name, street, zip) VALUES ('2f802845-447b-4caa-8783-2086a0a8d437', 'Peter', 'Mainstreet 7', '88888'); 2) Get created row SELECT * FROM table WHERE uuid='2f802845-447b-4caa-8783-2086a0a8d437';
Even though this is an older thread, there is a newer way to do this which avoids some of the pitfalls of the IDENTITY column in older versions of SQL Server, like gaps in the identity values after server reboots. Sequences are available in SQL Server 2016 and forward which is the newer way is to create a SEQUENCE object using TSQL. This allows you create your own numeric sequence object in SQL Server and control how it increments. Here is an example: CREATE SEQUENCE CountBy1 START WITH 1 INCREMENT BY 1 ; GO Then in TSQL you would do the following to get the next sequence ID: SELECT NEXT VALUE FOR CountBy1 AS SequenceID GO Here are the links to CREATE SEQUENCE and NEXT VALUE FOR
Complete solution in SQL and ADO.NET const string sql = "INSERT INTO [Table1] (...) OUTPUT INSERTED.Id VALUES (...)"; using var command = connection.CreateCommand(); command.CommandText = sql; var outputIdParameter = new SqlParameter("#Id", SqlDbType.Int) { Direction = ParameterDirection.Output }; command.Parameters.Add(outputIdParameter); await connection.OpenAsync(); var outputId= await command.ExecuteScalarAsync(); await connection.CloseAsync(); int id = Convert.ToInt32(outputId);
After Your Insert Statement you need to add this. And Make sure about the table name where data is inserting.You will get current row no where row affected just now by your insert statement. IDENT_CURRENT('tableName')