sql-server primary key (ID) does not increment correctly - c#

I am working on a project with C# and SQL Server 2016.
In SQL Server Management Studio I add a primary key to an existing table, by right clicking the table and choosing design table, it worked fine.
But as soon as I add some new users and deleted some users, it started behaving strange, I mean after id=4 next user should have id=5 but instead it was given id=7.
Screenshot of SSMS

Actually you have deleted the users with id 5 and 6. The counter for the auto increment is not reset or reversed automatically. Its the normal and standard behavior.

This may sound unbelievable, but if you want an incrementing record number, SQL Server has no support for you. A transaction that is rolled back or a server restart can leave holes in the numbers.
If you delete a row, you'll have to implement that manually. Say that records 1, 2 and 3 exist. You delete record 2. What number should the new order get? If you say 2, remember that means order 2 is created after order 3, which would confuse a lot of people.

Probably records with Id 5 and 6 ar been deleted

IDENITY T-SQL
Specifically the 'Reuse of values'
'For a given identity property with specific seed/increment, the identity values are not reused by the engine. If a particular insert statement fails or if the insert statement is rolled back then the consumed identity values are lost and will not be generated again. This can result in gaps when the subsequent identity values are generated. '
Hope this helps to explain

It might not just be that the records have been deleted. Every time you try to INSERT data into that table the seed will be incremented. Take, as a very simple example:
CREATE TABLE #Sample (ID int IDENTITY(1,1), String char(1));
GO
INSERT INTO #Sample (String) VALUES ('A'); --This'll get ID 1
GO
INSERT INTO #Sample (String) VALUES ('AB'); --This'll get ID 2, but fail insertion (due to truncation)
GO
INSERT INTO #Sample (String) VALUES ('C'); --This'll be ID 3.
GO
--Let's Check.
SELECT *
FROM #Sample;
GO
--The SAme is tue for Transactions.
BEGIN TRANSACTION;
INSERT INTO #Sample (String) VALUES ('Q'); --This'll get ID 4
ROLLBACK;
INSERT INTO #Sample (String) VALUES ('S'); --This'll get ID 5
SELECT *
FROM #Sample;
GO
--DELETE
--Let's delete EVERYTHING
DELETE
FROM #Sample;
INSERT INTO #Sample (String) VALUES ('A'); --This'll get ID 6, Not 1
SELECT *
FROM #Sample;
GO
--Finally, howerver, truncate:
TRUNCATE TABLE #Sample;
--Truncate RESETS the seed.
INSERT INTO #Sample (String) VALUES ('A'); --This'll be 1;
SELECT *
FROM #Sample;
GO
--Clean up
DROP TABLE #Sample;
Hope that helps.

Assuming that you have used the identity feature in SQL server. When you try to insert a new record into a table having an identity column, the identity value will be increased even if the insert failed due.
Suppose I have a table where the identity column SeqNo have the current value as 9 and incremented by 1.
I'm inserting a new record but it failed due to some data issues.
So I fixed the issues are tried re-inserting the same.
Assuming no other inserts happened during this time, the SeqNo for the new record should be 10, but it will be 11.
because SQL Server won't roll back the Identity Seed if the insert fails. So you will have to manually re-seed the column
Same in the case of delete and insert. I have the Maximum SeqNo as 5.I deleted the SeqNo 5 and inserted a new record, but for my new record, the SeqNo will be 6 (or the next identity value)
So, if you want to specify some values to the identity column, try inserting with SET IDENTITY INSERT ON. like this
SET IDENTITY INSERT YourTable ON
INSERT INTO YourTable(SeqNo,Name)
VALUES(5,'ABC')
SET IDENTITY INSERT YourTable OFF

When we delete of cancel(by pressing ESC button while filling values in table), it takes it as increment, you can truncate your table(
NOTE: Truncate will delete all values from your table
)

Related

How do I reset Auto-Increment to start from 1 in built-in SQL Database of C# after deleting contents from table?

How do I reset Auto-Increment to start from 1 in built-in SQL Database of C# after deleting contents from table ?
The problem I am facing is that, when I delete all the contents from the table with the "DELETE" query and again try to insert new data the "Id" will start from 100 whereas I am expecting it to be start from 1. Can anyone help me to solve this issue where the Primary Key i.e., "Id" starts from its seed which is "1" ?
you can set a new current identity value for the identity column with the query below
DBCC CHECKIDENT (mytable, RESEED, 0)

How to deleted record as false in SQL Server from winforms UI using c#?

I have a problem to set deleted record as false in my SQL Server.I tried a lot.
My problem is i have a table in some Of the columns id,name etc...id as primary
key constraint. When the user delete the record? so that record should be
present on the table. i will make that record as false in my table?
In future he want to add the record with the deleted id? we give the chance to
add a record with that id?
plz tell me the example of doing this? i tried a lot but i don't know. because
primary key doesn't accept duplicates so i strucked here.
My delete stored procedure:
If user press the delete button in my UI:
This stored procedure is execute in my back-end:
update table set id=id*-1, flag=1 where id=#id and flag=0;
In front i have shown record is deleted.
But if he want to add the record with that deleted id. Primary key voilation
error from my database.when he insert the record.
Thanks
Add a column DeleteFlag bit into the table, set to false by default.
Always add the where condition WHERE DeleteFlag = 0 to display data in UI
Update the column to true if user "delete" the record from UI
Do not alter primary key, they are not intended to change.
EDIT
To reuse the deleted Id, you can negate the Id and mark the record as deleted. However, this is not recommended to update the primary key in normal case.
example
UPDATE id = -1 * id, flag = 1 WHERE id = #id and flag = 0;
EDIT 2
Missed if the use delete the new record with same deleted id, just negate the id is not enough.
UPDATE t SET id = newId.Value, flag = 1, new_field=#id
FROM table t CROSS APPLY
(
SELECT CASE WHEN MIN(Id) >= 0 THEN -1 ELSE MIN(Id) - 1 END AS value
FROM table with(updlock)
) AS newId
WHERE t.id = #id AND flag = 0

Get last generated ID and add it to another table ASP.NET

How can I get get generated ID from primary key and then add it to another table in ASP.NET via SCOPE_IDENTITY?
For example:
Last generated ID on column NRRENDOR is number 26, I have deleted the rows. Now when I add datas to the database the nexy generated ID on NRRENDOR will be number 27. That number I want it to add to column NRD.
In your INSERT code, assuming it's in a stored procedure, using SCOPE_IDENTITY will get you the last identity that was inserted, which you can either reuse in the stored procedure or return to your app to use in another statement.
Some dummy SQL to demonstrate:
INSERT INTO NRRENDOR(SomeColumn) VALUES(1)
DECLARE #LastID int
// set #LastID to the last id inserted
SELECT #LastID = SCOPE_IDENTITY()
// to use in same procedure
INSERT INTO NRD (SomeColumn) VALUES(#LastID)
// to return it to code - or you could use an output parameter
SELECT #LastID
What has this got to do with ASP.NET? SQL would suffice.
INSERT INTO [Table2]( NRD)
SELECT MAX(NRRENDOR)
FROM Table1
' WITH (ROWLOCK, XLOCK, HOLDLOCK)
The correct way to do it will be to use #SCOPE_IDENTITY after you perform insertion as Tanner suggested. It will be worth noting that there is another way to get the current identity, ie, IDENT_CURRENT. You can use it like this
SELECT IDENT_CURRENT('Table1') + 1 as Current_Identity
Please note this too
Be cautious about using IDENT_CURRENT to predict the next generated
identity value. The actual generated value may be different from
IDENT_CURRENT plus IDENT_INCR because of insertions performed by other
sessions.
This comment from marc_s sums it all. How to get the next identity value from SQL Server

Making a substring plus data from sql database column

I am trying to create, lets say a user ID. I have a sql server database and i have a user webpage developed in asp.net. On my user page, a user fill out the information in the text boxes(First Name, Last Name, Middle Initial and so on) and when a user clicks a submit button, the entered information is added to a database. I have an auto increment column in the database, so when the information is added to the database the row has a auto increment number, for example 1. Each time the new row is added the auto increment number rises on one.
I want to create an unique UserID. It should contain the first 4 letters of a Last Name, which user fills out on a user web page and the auto increment number from the database. I have a code to retrieve the first 4 letters of the last name ( string FirstFour = txtNewUserLN.Text.Substring(0, 4);) but i need to add auto increment number from the database to that string.
Could anyone help me with it?
Create an sql user defined function in sql database
for create an function
use
CREATE FUNCTION ucernamehandle(#Lastname)
RETURNS nchar(50)
AS
BEGIN
DECLARE #idfromauo int;
DECLARE #newusernem nchar(50);
SET #idfromauo =IDENT_CURRENT('yourtablename');
return #Lastname+#idfromauo;
END
and then use it in inset statement like
INSERT INTO yourtablename (LastName) VALUES (ucernamehandle(#Lastname))
then exactly you will get witch you want
welcome for your thank's
best of luck
My guess is you are going to have to do an insert and then an update. Something to watch out for - if you use anything that checks for the last or just inserted identity value, make sure you put it in a transaction. If you don't you could have other processes adding a record before you update.
So try something like this:
insert into UserList(LastName, FirstName, ...) values (#LastName, #FirstName)
declare #UserID varchar(500)
set #UserID = left(#LastName, 4) + convert(varchar(10), SCOPE_IDENTITY())
update UserList set UserID = #UserID where RowID = Scope_identity()

How do I structure this transaction?

We have an ASP.NET/MSSQL based web app which generates orders with sequential order numbers.
When a user saves a form, a new order is created as follows:
SELECT MAX(order_number) FROM order_table, call this max_order_number
set new_order_number = max_order_number + 1
INSERT a new order record, with this new_order_number (it's just a field in the order record, not a database key)
If I enclose the above 3 steps in single transaction, will it avoid duplicate order numbers from being created, if two customers save a new order at the same time? (And let's say the system is eventually on a web farm with multiple IIS servers and one MSSQL server).
I want to avoid two customers selecting the same MAX(order_number) due to concurrency somewhere in the system.
What isolation level should be used? Thank you.
Why not just use an Identity as the order number?
Edit:
As far as I know, you can make the current order_number column an Identity (you may have to reset the seed, it's been a while since I've done this). You might want to do some tests.
Here's a good read about what actually goes on when you change a column to an Identity in SSMS. The author mentions how this may take a while if the table already has millions of rows.
Using an identity is by far the best idea. I create all my tables like this:
CREATE TABLE mytable (
mytable_id int identity(1, 1) not null primary key,
name varchar(50)
)
The "identity" flag means, "Let SQL Server assign this number for me". The (1, 1) means that identity numbers should start at 1 and be incremented by 1 each time someone inserts a record into the table. Not Null means that nobody should be allowed to insert a null into this column, and "primary key" means that we should create a clustered index on this column. With this kind of a table, you can then insert your record like this:
-- We don't need to insert into mytable_id column; SQL Server does it for us!
INSERT INTO mytable (name) VALUES ('Bob Roberts')
But to answer your literal question, I can give a lesson about how transactions work. It's certainly possible, although not optimal, to do this:
-- Begin a transaction - this means everything within this region will be
-- executed atomically, meaning that nothing else can interfere.
BEGIN TRANSACTION
DECLARE #id bigint
-- Retrieves the maximum order number from the table
SELECT #id = MAX(order_number) FROM order_table
-- While you are in this transaction, no other queries can change the order table,
-- so this insert statement is guaranteed to succeed
INSERT INTO order_table (order_number) VALUES (#id + 1)
-- Committing the transaction releases your lock and allows other programs
-- to work on the order table
COMMIT TRANSACTION
Just keep in mind that declaring your table with an identity primary key column does this all for you automatically.
The risk is two processes selecting the MAX(order_number) before one of them inserts the new order. A safer way is to do it in one step:
INSERT INTO order_table
(order_number, /* other fields */)
VALUES
( (SELECT MAX(order_number)+1 FROM order_table ) order_number,
/* other values */
)
I agree with G_M; use an Identity field. When you add your record, just
INSERT INTO order_table (/* other fields */)
VALUES (/* other fields */) ; SELECT SCOPE_IDENTITY()
The return value from Scope Identity will be your order number.

Categories